2017-07-19 57 views
0

任何人都可以在TypeScript(2.4.1)中解释以下行为吗?TypeScript中的奇怪联合类型行为

场景:我有一个可能是“红色”或“红色和圆形”(修改)的按钮。我想有以下语法来形容它:

button.mods = "red"; 
button.mods = ["red", "round"]; 
button.mods = { red: true, round: false }; 

来形容这一切,我用了以下接口:

interface HasMods<T extends string>{ 
    mods: T | T[] | { [key in T]?: boolean } 
} 

interface Button extends HasMods<"round" | "red"> { 
} 

好了,现在我们可以做一些测试:

let b: Button; 
b.mods = "red"; //ok, correct 
b.mods = "green"; //error, correct 

b.mods = ["red"]; //ok, correct 
b.mods = ["green"]; //error, correct 

b.mods = {red: true}; //ok, correct 
b.mods = {red: true, green: true}; //error, correct 

到目前为止,一切都很完美。 但现在是个谜:

b.mods = {red: true, map: false}; //ok, why ??? 

为什么值“地图”有效期为我喜欢的类型的对象{[在T键] ?:布尔},其中T是“红” | “回合”? “地图”既不是“红色”,也不是“圆形”。

实际上,所有的阵列方法是有效的在这里 - “每一个”,“copyWithin”,等等

+0

我相信默认情况下,typescript不会执行多余的密钥检查。它只验证对象中需要什么。 –

+1

为什么不呢?在{red:true,green:true}中,它完美地表示可以使用红色,但绿色不能。 – dennis

回答

2

如果走在阵列的定义一看,“地图”是一属性。

因此,当你比较“映射T”这是真的,因为它是被一个数组结构内进行比较,如果它是一个对象会是假的

console.log("map" in {"element":4}) // false 
 
console.log("map" in [4]) //true

+0

是的,我明白这一点。但为什么是一个数组? T应该是类型“红色”|向编译器“四舍五入”。 – dennis

+1

'HasMods <“round”| “red”> * *可能是一个数组,这就是TypeScript [处理](https://github.com/Microsoft/TypeScript/issues/14383)联合类型过多属性的方式。 – jcalz