TypeScript允许为可以包含任何属性的对象定义接口:
interface NumberHash {
[key: string]: number;
}
let numbers: NumberHash = {
zero: 0,
one: 1,
pi: 3.14
};
从这样的对象中查找属性时,它们会按预期返回number
。
let key = 'pi';
let pi = numbers[key];
console.log(pi.toFixed(1)); // all is well
但是,在查找未知属性时,它们仍会以number
的形式返回,即使它们实际上是undefined
。
let key = 'foo';
let foo = numbers[key]; // `foo` becomes `undefined`
console.log(foo.toFixed(1)); // errors at runtime
上面的代码在运行时抛出TypeError
,但在编译期间不抛出。为什么TypeScript在编译期间没有捕获到这个错误?
答案 0 :(得分: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'
另见:
答案 1 :(得分:0)
在您的示例中,很清楚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'];