如果条件“property in object”为真,为什么TypeScript不推断object[property]的类型为object值的联合类型?

fumotvh3  于 2023-01-18  发布在  TypeScript
关注(0)|答案(1)|浏览(221)

我正在尝试访问object[property],TypeScript抛出了element implicitly has any type错误。

const getValue = (key: string) => {
  const object = {
    property0: 14
    property1: -3
  }

  if (!(key in object)) {
    throw new Error(`Invalid key: ${key}`)
  }

  return object[key]
}

如果我们不知道property in object是否为真,我们必须自己为TypeScript提供索引签名,也就是说,如果我们从该函数中删除了if(!(key in object))条件,TypeScript * 应该 * 抛出错误,直到我们手动注意到object的索引签名。
但是看起来,如果我们在编译时知道keyobject中,当我们执行return语句时,TypeScript不应该为这个函数抛出这样的错误,而是应该推断getValue的返回类型为number
我可以通过手动记录object的索引签名来解决此问题:

interface ObjectWithOnlyNumberProperties {
  [key: string]: number
}

const getValue = (key: string) => {
  const object: ObjectWithOnlyNumberProperties = {
    property0: 14
    property1: -3
  }

  if (!(key in object)) {
    throw new Error(`Invalid key: ${key}`)
  }

  return object[key]
}

但似乎我不必这样做,而且object[key]的类型应该在编译时可以推断为typeof property0 | typeof property1,因为我们知道key in object是真的。

yhqotfr8

yhqotfr81#

抄袭罗曼·洛朗的评论,完美地回答了这个问题!
在编译时,TypeScript处理的是类型,而不是实际对象。默认情况下,{ property0: 14, property1: -3 }的类型为{ property0: number, property1: number }。TypeScript中的类型是最小的契约一致性,因此就TypeScript所知,{ property0: number, property1: number }类型可以引用像{ property0: 14, property1: -3, property2: "string" }这样的实际对象。显然,我们在代码中知道它不会。但是TypeScript并不知道这一点,正如上面的例子所表明的,object[property]的类型是any,因为property2可以是 * 任何 * 类型,而不仅仅是string
更新:根据geoffrey的评论,如果你使用的是目标库es2022或更新版本,你也应该更新上面的代码,使用Object.hasOwn(object, property)代替property in object,以防止原型污染。

相关问题