我想输入一个允许默认值的数据库插入函数: (我正在使用type-fest的SetOptional)
function defaultInsert<T, D = Partial<T>>(data: SetOptional<T, keyof D>, defaults: D) {
我想用SetOptional表示的是,数据对象应包含T中的任何内容,而不是默认值(D)中指定的内容,但允许覆盖默认值中的任何内容。
不幸的是,这导致以下错误
Type 'keyof D' does not satisfy the constraint 'keyof T'.
Type 'string | number | symbol' is not assignable to type 'keyof T'.
Type 'string' is not assignable to type 'keyof T'.(2344)
Typescript playground以获得更详细的示例。
我是否有任何办法可以将Partial过滤为仅包含T的键,因为我假设这是问题所在,原因是D可能包含不在T中的多余属性?
非常感谢
编辑:@Alex Chashin的建议,另一个TS Playground使用这些键作为定义默认值的方法。
EDIT2:使用UPD2 @Alex Chashin中提供的解决方案更新了playground
EDIT3:更新了前面的示例,因此默认值也可以省略:playground
答案 0 :(得分:0)
UPD2: 因此,我唯一能想到的就是这个世界(ts playground):
function defaultInsert<T, D extends keyof T>(
data: Omit<T, D> & Partial<Pick<T, D>>,
defaults: Pick<T, D>
): void {
// Hover over this variable to see its type
const doc = { ...data, ...defaults } as T
insert<T>(doc)
}
这将通过您提供的测试,但是很遗憾,{...data, ...default}
不能被推断为T
,因此您必须进行转换。我认为这没什么大不了的,因为这种类型转换只需要4个符号。唯一的问题是,每次编写示例D
时,都必须根据需要为keyof typeof personDefaults
显式提供密钥。
UPD:
使用一种可能的解决方案链接到TS游乐场:playgroung
原始答案:
因此,Partial<T>
已经使T
的所有键为可选,因此在执行SetOptional
之后,您无需使用Partial
。如果您希望所有数据键是可选的,请使用以下命令:
function defaultInsert<T>(data: Partial<T>, defaults: T) {
// ...
}
请注意,defaults
的类型为T
,而不是Partial<T>
,因为如果是Partial<T>
,则可以提供不完整为data
的文档和文档它不像defaults
那样完整,因此合并它们将不会提供完整的文档,这可能对您造成问题。如果不是,请将T
替换为Partial<T>
,这很难判断,因为您没有提供所有代码。
如果只希望某些键是可选的,请执行以下操作:
function defaultInsert<T, Keys extends string>(
data: SetOptional<T, Keys>,
defaults: { [key in Keys]: T[key] }
) {
// ...
}
像这样,您只需要提供可选键的默认值,而不是所有键的默认值
您也可以将defaults
类型的
Omit<Partial<T>, Keys> & { [key in Keys]: T[key] }
// or if you use your `SetOptional`
SetOptional<T, Exclude<keyof T, Keys>>
当您为非可选键提供默认值时,这样打字稿就不会抱怨
然后使用
defaultInsert<{ foo: number, bar: string }, 'foo'>(
{ bar: 'abc' },
{ foo: 12345 }
)