这里的问题实际上不是递归(这是允许的),而是您指出的冲突签名。
我不确定当前行为的反面是否正确。对我来说,这似乎是一个主观决定,可以通过两种方式进行。按原样接受示例意味着您正在隐式合并定义;您可以查看其中一条线并假设界面的效果,而另一条线会改变结果。写起来确实感觉更自然,但我不确定它是否像您通常期望的那样安全,类型定义会失败。
无论如何。 TypeScript 确实允许与您期望的行为类似的行为,但您必须明确,因为字符串键也可以是string 或number 类型。这将起作用:
interface CSSProperties {
marginLeft?: string | number,
[key: string]: CSSProperties|string|number,
}
比如上面的接口,这是有效的:
let a: CSSProperties = {
marginLeft: 10,
name: {
marginLeft: 20,
}
};
这不是:
let a: CSSProperties = {
marginLeft: 10,
something: false, // Type 'boolean' is not assignable to type 'string | number | CSSProperties'.
something: new RegExp(/a/g), // Type 'RegExp' is not assignable to type 'CSSProperties'.
name: {
marginLeft: 20,
},
car: ["blue"], // Type 'string[]' is not assignable to type 'CSSProperties'.
};
它会正确认识命名的成员:
let name1: string | number = a.marginLeft; // OK, return type is string | number
a.marginLeft = false; // Blocked, Type 'false' is not assignable to type 'string | number'.
a["whatever"] = false; // Blocked, Type 'false' is not assignable to type 'string | number | CSSProperties'.
a["marginLeft"] = false; // Blocked, Type 'false' is not assignable to type 'string | number'.
然而,这里的问题是您需要在阅读时强制转换其他动态成员 - 它不会知道它是 CSSProperties。
这不会被阻止:
a["whatever"] = 100;
它会抱怨这个:
let name3: CSSProperties = a["name"]; // Type is CSSProperties | string | number
但是,如果您明确地进行类型转换,这将起作用:
let name3: CSSProperties = a["name"] as CSSProperties;