TS2536:即使类型必须是键,也不能用作索引?

时间:2019-08-22 06:50:37

标签: typescript

我正在尝试为此功能添加类型:

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[]

typeof keyof

1 个答案:

答案 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 

play

此值是受限制的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 

play

编辑如注释中所指出的那样,重载在这里不能很好地工作,因为如果值不匹配,编译器将继续进行字符串重载,并且自{{1} }是value,第一个选项是我们要获得的最接近的选项。