【问题标题】:typescript "in operator" does not work with string index打字稿“in operator”不适用于字符串索引
【发布时间】:2021-10-30 00:52:26
【问题描述】:

代码

const test = {
  a: 'b',
  c: 'd',
} as const;

const toPick: string = 'a';

if (toPick in test) {
  console.log(test[toPick]); // not "b" (Error)
}

没有as const也报错

错误

元素隐含地具有“任何”类型,因为类型的表达式 'string' 不能用于索引类型'{ readonly a: "b"; readonly c: "d"; }'

没有找到带有“字符串”类型参数的索引签名 输入'{ readonly a: "b"; readonly c: "d"; }'

typescript playground

【问题讨论】:

标签: typescript


【解决方案1】:

您可以推断它,但您需要删除显式 string 类型:

const test = {
  a: 'b',
  c: 'd',
} as const;

const toPick = 'a';

if (toPick in test) {
  const x = test[toPick] // b
}

因为a 使用了string 类型,而test 没有索引属性TS。

大多数时候你不应该使用显式类型。 TS 应该可以推断出来。

如果您已按目的使用了string 显式类型,那么您可以使用自定义类型保护:

const test = {
    a: 'b',
    c: 'd',
} as const;

const toPick: string = 'a';

const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
    : obj is Obj & Record<Prop, unknown> =>
    Object.prototype.hasOwnProperty.call(obj, prop);

if (hasProperty(test, toPick)) {
    test[toPick]
}

如果您不想使用自定义类型保护并且可以删除 as const,则可以为 test 提供显式索引类型:

const test: Record<string, string> = {
    a: 'b',
    c: 'd',
};

const toPick: string = 'a';


if (toPick in test) {
    test[toPick]
}

【讨论】:

  • 如果toPick 的类型为'a',那么根本不需要测试toPick in test;我认为问题的重点是在这种情况下将string 类型的变量缩小为keyof typeof test 类型。
  • @kaya3 感谢您的澄清,我进行了更新并添加了几个解决方法
【解决方案2】:

Typescript 通常不会证明代码的所有可证明属性,也不会尝试证明。编译器会进行类型缩小,但仅在特定情况下根据特定规则进行,因此它并不总是将变量缩小到人类能够推断出的最具体的类型。

在这种情况下,您使用的是 in 运算符,即 Typescript does have a type narrowing rule for - 但该规则用于缩小对象的类型,而不是属性的类型。根据文档,此规则仅适用于属性为字符串文字且对象具有联合类型的情况。

【讨论】:

    【解决方案3】:

    收窄是行不通的;它旨在缩小test 的类型。使用反射 API 吗?

    const test = {
      a: 'b',
      c: 'd',
    } as const;
    const toPick: string = 'a';
    
    if (toPick in test) {
      console.log(Reflect.get(test,toPick)); 
    }
    
    //or
    
    if (Object.getOwnPropertyNames(test).includes(toPick)) {
      console.log(Reflect.get(test,toPick));
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-20
      • 1970-01-01
      • 2017-04-19
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 2017-03-19
      相关资源
      最近更新 更多