The Why
在打字稿中,|
不是运算符*,它表示该类型是左侧类型和右侧类型的联合。如果您想了解原因,了解这一点很重要{a:number,b:number} | {a:number,c:number,d:number}
allows {a:number,b:number,c:number}
.
声明联合时,您告诉编译器可分配给联合的类型应该可分配给其中的至少一个成员。考虑到这一点,让我们检查一下{a:number,b:number,c:number}
从这个角度键入。
联盟的左侧成员是{a:number,b:number}
,这意味着可分配给它的类型必须至少具有 2 个类型的属性number
: a
and b
(有一个概念超额财产检查 https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks对于对象字面量,但是,正如已经提及 https://stackoverflow.com/questions/66382997/typescript-how-to-define-a-true-logical-or-of-object-types-no-mixing-of-diffe#comment117358376_66382997作者:T.J.克劳德,这不适用于工会)。从手册 https://www.typescriptlang.org/docs/handbook/interfaces.html#our-first-interface**:
编译器仅检查是否至少存在所需的并且与所需的类型匹配
因此,自从{a:number,b:number,c:number}
可分配给{a:number,b:number}
不需要更多的检查 - 该类型至少满足联合的一项要求。顺便说一句,这种行为完全符合逻辑或的真值表,这类似于并集。
您尝试通过将类型包装到元组中来解决此问题依赖于裸露与包裹 https://stackoverflow.com/a/51651684/11407695类型参数行为。因为您将类型包装在元组中,所以编译器会比较tuples一种元素彼此的关系。显然,第三个元组与第一个和第二个元组不同,这给了您所需的结果。
The What
您真正想要的是逻辑异或所表现出的行为:其中之一,但不是两者。除了使用标记类型 https://mariusschulz.com/blog/tagged-union-types-in-typescript (提及 https://stackoverflow.com/questions/66382997/how-to-define-a-true-logical-or-of-object-types-no-mixing-of-different-object-k?noredirect=1#comment117358438_66382997作者:T.J. Crowder),我们可以定义一个实用程序,将一对类型转换为“来自 A 的所有 props 都存在于两个类型中,但不单独存在于 A 类型中”的并集:
type XOR<A,B> = ({ [ P in keyof A ] ?: P extends keyof B ? A[P] : never } & B) | ({ [ P in keyof B ] ?: P extends keyof A ? B[P] : never } & A);
这是它的工作原理(该实用程序的权衡是多余的属性被泄露给智能感知,但由于以下原因,人们立即不允许指定它never
):
const t0:XOR<TA,TB> = {a:1} //property 'b' is missing
const t1:XOR<TA,TB> = {a:1,b:1} // OK
const t2:XOR<TA,TB> = {a:1,c:1,d:1} // OK
const t3:XOR<TA,TB> = {a:1,b:1,c:1} // types of property 'c' are incompatible
操场 https://www.typescriptlang.org/play?#code/C4TwDgpgBAKgglAvFA3gQwFwDsCuBbAIwgCcAaA7fI4gXwFgAoUSWAISVU10JNIGNKPMgBNB1eg0bNoADQDyAJQA8cUqwB8HABQooAbSgAFKAEssUANYQQAewBmUBAF0oAfgxGoEAB7AIWYQBnS2t7KHZXRz1DFw8sCAA3EigaKAAycIBKKAAfKB19TzMQ2wd2F3dPHz8A4KtSxzdw6NioeKTiFPTHTIBuRkY+GyxA4ChgAAYMeWV4UhgNDnQMAEZUgHp1sGIbSGJQKAByAkPTYLwTQMCzAHNB4dHxlenFJTmFzWRllfJVjfWoHIANL3EZjYAAJhes1UHyWmB+Ah+ojWUE2gKBUFBj2AAGZoW9YYsvgjfoi-miAdJgmFtrsSAdDnxTmhiNAzEM8GA0MATAQADYQbHggAsBPexNQUAEEJSvUpFyut3GAAtoHYbPz+TYAO7Kul7XkQYJ2HZ4cbgaCHBaHDxoUhQYRAA
* 的概念|
作为一名经营者存在于第一次修订 https://stackoverflow.com/revisions/66382997/1后来被删掉了
** 需要注意的是,这并不意味着all当找到匹配时检查短路。在这种情况下,联合体的所有成员本身都是对象文字,因此对已知属性的约束仍然适用于每个成员,如果在赋值期间存在未知属性,则会导致 TS2322 错误:
const t4:XOR<TA,TB> = {a:1,b:1,c:1, g:3} //Object literal may only specify known properties