我正在尝试为此功能添加类型:
setKey(key: keyof TData|string|string[], value: typeof key extends keyof TData ? TData[typeof key] : any) {
this.set(setIn(key,value));
}
基本上key
应该是keyof TData
,但是它也接受fancy.dotted.syntax
和['array','path','syntax']
,这很难正确键入-但是如果您 do 提供一个简单的索引,然后我还要为该值输入类型补全。我以为可以为此使用条件类型,但也许TS编译器无法处理?还是我做错了?
基本上,我希望typeof key extends keyof TData ?
会缩小key
类型的范围,以便随后的工作可行,但TS仍然认为它可能是string|string[]
。
答案 0 :(得分:1)
typeof key
始终是声明的类型keyof TData|string|string[]
,无论您传递给函数什么内容。您要捕获呼叫站点类型,为此,您需要使用类型参数(限制为扩展keyof TData|string|string[]
)。
class DataOwner<TData> {
setKey<TKey extends keyof TData|string|string[]>(key: TKey, value: TKey extends keyof TData ? TData[TKey] : unknown) {
}
}
let o = new DataOwner<{ a: string }>();
o.setKey("a", "") // ok
o.setKey("a", 1) // errr
o.setKey("x", 1) // ok, since key can be any aritrary string
此值是受限制的IMO。由于key
可以是任何字符串,因此传入不是键的任何内容都不会出错。
此外,由于TKey
可以是string
,因此即使扩展keyof TData
也不会得到建议。就关键建议而言,多个重载将更好地工作,但仍然会遇到我指出的第一个问题:
class DataOwner<TData> {
setKey<TKey extends keyof TData>(key: TKey, value: TData[TKey]): void
setKey(key: string|string[], value: unknown): void
setKey(key: keyof TData|string|string[], value: unknown) {
}
}
let o = new DataOwner<{ a: string }>();
o.setKey("a", "") // ok
o.setKey("a", 1) // errr
o.setKey("x", 1) // ok, since key can be any arbitrary string
编辑如注释中所指出的那样,重载在这里不能很好地工作,因为如果值不匹配,编译器将继续进行字符串重载,并且自{{1} }是value
,第一个选项是我们要获得的最接近的选项。