编译器不理解“嵌套可区分联合”的概念。如果联合的成员共享共同的“判别”属性,则类型是受判别联合。判别属性通常是单例/文字类型,例如true
or "hello"
or 123
甚至null
or undefined
. You can't不过,使用另一个受歧视的联合作为判别器本身。如果可以的话那就太好了,因为这样受歧视的联合可以像您所做的那样从嵌套属性中传播。有一个建议位于微软/TypeScript#18758 https://github.com/microsoft/TypeScript/issues/18758允许这样做,但我没有看到任何动静。
就目前情况而言,类型TotalData
不是一个受歧视的联盟。这只是一个联盟。这意味着编译器不会尝试处理类型的值TotalData
as 只 either Condition1
or Condition2
。因此,如果您编写测试代码,您可能会遇到问题data.abilities.canManage
并期望编译器理解其含义:
function hmm(x: TotalData) {
if (x.abilities.canManage) {
x.extraProp.toFixed(); // error!
// ~~~~~~~~~~~ <--- possibly undefined?!
}
}
如果你想这样做,你可能会发现自己需要写用户定义的类型保护函数 https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards反而:
function isCondition1(x: TotalData): x is Condition1 {
return x.abilities.canManage;
}
function hmm(x: TotalData) {
if (isCondition1(x)) {
x.extraProp.toFixed(); // okay!
}
}
您在这里遇到的具体问题在哪里data
被视为有效TotalData
与如何有关超额财产检查 https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks被执行。 TypeScript 中的对象类型是“开放”/“可扩展”,而不是“封闭”/“exact https://github.com/microsoft/TypeScript/issues/12936”。您可以在不违反类型的情况下添加类型定义中未提及的额外属性。因此编译器不能完全禁止多余的属性;相反,它使用启发式方法来尝试找出这些属性何时是错误的以及何时是错误的。故意的。使用的规则主要是:如果您正在创建一个全新的对象字面量,并且它的任何属性未在其使用的类型中提及,则会出现错误。否则不会出现错误。
If TotalData
是一个受歧视的工会,你会得到你期望的错误data
因为data.abilities.canManage
会导致编译器缩小范围data
from TotalData
to Condition2
其中没有提到extraProp
。但事实并非如此,所以data
遗迹TotalData
which does提到extraProp
.
有人提出,在微软/TypeScript#20863 https://github.com/microsoft/TypeScript/issues/20863,对非歧视工会的超额财产检查应更加严格。我非常同意;混合和匹配不同联合成员的属性似乎不是常见的用例,因此警告可能会有所帮助。但同样,这是一个长期存在的问题,我没有看到任何进展。
为此,您可以做的一件事是更明确地说明您想要防范的多余属性。类型的值{a: string}
可以有一个b
类型的属性string
,但是类型的值{a: string, b?: never}
不能。所以后一种类型将阻止类型的属性b
不依赖编译器的启发式进行过多的属性检查。
在你的情况下:
type Foo = {
abilities: {
canManage: boolean
};
extraProp?: never
}
其行为将与您原来的非常相似Foo
定义,但现在你得到这个错误:
const data: TotalData = { // error!
// -> ~~~~
// Type '{ abilities: { canManage: false; }; extraProp: number; }'
// is not assignable to type 'TotalData'.
abilities: {
canManage: false,
},
extraProp: 5
}
编译器无法再协调data
与任一Condition1
or Condition2
,所以它抱怨。
好的,希望有帮助;祝你好运!
Playground 代码链接 https://www.typescriptlang.org/play?#code/C4TwDgpgBAYg9nKBeKBvAUFLUCGAjASwBsDgCIBnALjU23oGMcA7AWRZwHMIa8EiILOlgC+AbmFQA9FKgQAHsABOOAApK4YAPw1mEAG4Ql02QFdmDOAFsrEZsCjAAFgQroR6T6EhQAQjmMUDHp8YlJyalp6RhZ2Zi4eKD44ASF6D3oFZTUNMF1TKzwjdy9waABhOGYAE3CqgEZkKOxQkjJKGmDorCY2Dm4aZVMISQ8RKAAyPwDSn0qauuYAJiaurFbwjubu3riEmgAzHCIKEfT3SdgEWegAFThgY4ARHEem+dqyBqgAHygPxZLTyWZgUBzVV44Gj3R5EF5vIImORKDRKACEkhkUAAtAA+KAAPyJBMxsluZSgAHJULhCG0Ip0oLt+okjicIGIoOI5IoVOpNPlCkZOSJKVBXFBmA9cBQKAROPE8AJHIhvNBKTDnpDKQA6SQbdqRNbRZnxAZQNmnAA0oxtmV5OQFUAArCV0AdzAwvsxxRQAd76gAKeTQh5ax4ASho8l9-yqnwI32NSggwFMSh98h1BoiOtNCQkHndnu9UCcNmDodh8JwEdokgIBygwezdM2FDzsRZdeN9CzWT5uR1wDgMAI8gg1UDEc5WKMqIx9CxhOJq+JUAAPNjt1AwHBZQQlSAoOZqhADgQ9NUtIvsOMIOzttF+w7+WBZ7J53AlKNPPRG82rj+omzBBvIEY9pIfY6gOjpgMOo7jpO04fpKiBfj+6RyI+vbYC+2RvqhGG-h4QA