【问题标题】:Why does TypeScript not check for undefined when looking up properties from objects?为什么 TypeScript 在从对象中查找属性时不检查未定义?
【发布时间】:2026-01-07 23:25:02
【问题描述】:

TypeScript 允许为可以包含任何属性的对象定义接口:

interface NumberHash {
    [key: string]: number;
}

let numbers: NumberHash = {
    zero: 0,
    one: 1,
    pi: 3.14
};

当从此类对象中查找属性时,它们会返回为 numbers,正如预期的那样。

let key = 'pi';
let pi = numbers[key];

console.log(pi.toFixed(1));  // all is well

但是,在查找未知属性时,它们仍然返回为numbers,即使它们实际上是undefined

let key = 'foo';
let foo = numbers[key];  // `foo` becomes `undefined`

console.log(foo.toFixed(1));  // errors at runtime

上面的代码在运行时抛出TypeError,但在编译期间不会。为什么 TypeScript 在编译过程中没有捕捉到这个错误?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    使用strictNullChecks 编译器选项,接口NumberHash 可以声明如下:

    interface NumberHash {
        [key: string]: number | undefined;
    }
    

    然后:

    let numbers: NumberHash = {};
    let foo = numbers['foo'];
    
    console.log(foo.toFixed(1));  // error at compile time: Object is possibly 'undefined'
    

    另见:

    【讨论】:

      【解决方案2】:

      在您的示例中,您的 NumberHash 对象上将存在和不存在哪些属性非常清楚 - 它们在分配给您的 numbers 变量的对象文字中明确指定。有理由认为这是 TypeScript 在编译时可以防范的。

      不过,举个更动态的例子:

      interface NumberHash {
          [key: string]: number;
      }
      
      let numbers: NumberHash = {};
      
      const max = Math.random() * 100;
      for (var i = 0; i < max; i++) {
          numbers[i.toString()] = i;
      }
      
      let foo = numbers["42"];
      
      // is foo undefined?  Who knows! Depends
      // on what Math.random() returned.
      console.log(foo.toFixed(1));   
      

      在编译时,编译器无法知道Math.random() 在运行时会返回什么。因为编译器必须同时处理您的示例和我的示例,所以它让开发人员确保密钥存在。

      如果您知道编译时NumberHash 对象中将存在的属性,则可以将此数据结构重写为一个类:

      class Numbers {
          public static readonly zero: number = 0;
          public static readonly one: number = 1;
          public static readonly pi: number = Math.PI;
      }
      
      // both of these will compile without errors
      let foo = Numbers['zero'];
      let bar = Numbers.one;
      
      // Compiler error: Element implicitly has an 'any' type 
      // because type 'typeof Numbers' has no index signature.
      let baz = Numbers['foo'];
      

      【讨论】:

        最近更新 更多