为什么 TypeScript 类型保护“in”不将类型缩小为 keyof 类型?

And*_*nti 4 type-systems typescript

考虑这个代码:

const obj = {
    a: 1,
    b: 2
}

let possibleKey: string = 'a'

if (possibleKey in obj) console.log(obj[possibleKey])
Run Code Online (Sandbox Code Playgroud)

什么时候possibleKey in obj为真,我们知道它possibleKey有 type keyof typeof obj,对吧?为什么 TypeScript 类型系统没有检测到并缩小string到该类型?相反,它说:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: number; b: number; }'.
Run Code Online (Sandbox Code Playgroud)

jon*_*rpe 7

根据文档

对于n in x表达式,其中n是字符串文字或字符串文字类型并且x是联合类型,“真”分支缩小到具有可选或必需属性的类型n,而“假”分支缩小到具有可选或缺失的类型财产 n

换句话说,n in x缩小x,不n,并且仅用于字符串文字或字符串文字类型in联合类型。要使该表达式起作用,您必须向编译器提供更多信息,例如使用类型断言

if (possibleKey in obj) {
  console.log(obj[<keyof typeof obj>possibleKey]);
}
Run Code Online (Sandbox Code Playgroud)

  • 一个[不缩小“n”的原因](https://github.com/microsoft/TypeScript/issues/18282#issuecomment-327636329)是“x”对象可能具有“x”中未提及的属性类型(即对象类型不[准确](https://github.com/microsoft/TypeScript/issues/12936))。不过,当从问题中的“{a:1, b:2}”之类的对象文字推断出“x”的类型时,这并不适用,但我猜他们不想特殊情况。如果这是常见操作,则具有签名“&lt;T extends object&gt;(k: PropertyKey, o: T) =&gt; k is keyof T”的用户定义类型保护可能会有所帮助。 (3认同)