想必图书馆作者决定UnionOf<A | B | C>
应该产生相同的结果UnionOf<A> | UnionOf<B> | UnionOf<C>
,以及定义_UnionOf
没有那样做。这O extends unknown ? ... : never
check 看起来似乎什么也没做,却导致了这种情况的发生。
表达式看起来什么也没做,但实际上分布在联合中,当T
是泛型类型参数:
T extends unknown ? ... : never
T extends any ? ... : never
T extends T ? ... : never
If T
is a 类型参数,如在generic https://www.typescriptlang.org/docs/handbook/2/generics.html功能function foo<T>(/*...*/): void
或通用接口interface Foo<T> {/*...*/}
,然后是一种形式T extends XXX ? YYY : ZZZ
is a 分配性的条件类型 https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types.
It 分发条件检查unions https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types in T
. When T
指定了某种特定类型,编译器将该类型拆分为其联合成员,评估每个此类成员的检查,然后将结果连接回新的联合。因此,如果F<T>
分配给各个工会,然后F<A | B | C>
将与以下相同F<A> | F<B> | F<C>
.
并非所有类型函数都可以跨联合分配。例如,the keyof操作员 https://www.typescriptlang.org/docs/handbook/2/keyof-types.html#the-keyof-type-operator不会将输入的并集转换为输出的并集:
type KeyofA = keyof {a: string}; // "a"
type KeyofB = keyof {b: number}; // "b"
type KeyofAorB = keyof ({ a: string } | { b: number }); // never
相似地,_UnionOf
不跨工会分配(与它使用的事实有关)keyof
在其定义中):
type Oops = _UnionOf<{ a: string } | { b: number }>
// never
如果你有一个类型函数not工会和你的分配want确实如此,您可以将其包装在分布式条件类型中:
type DistribKeyof<T> = T extends unknown ? keyof T : never;
type UnionKeyofAorB = DistribKeyof<{ a: string } | { b: number }>; // "a" | "b"
因此UnionOf
is跨工会分配:
type Correct = UnionOf<{ a: string } | { b: number }>
// string | number
Playground 代码链接 https://www.typescriptlang.org/play?#code/C4TwDgpgBA0hIHsBmBBKBeKBreyoG8oBDALigGdgAnASwDsBzKAXwG4oB6DqAIiJ4BQoSLFxIAQhmxiCUAEZk6AVwC2ciFRbsuvOYOHQ4iVAiqTMOY1AAUhUhWr0mzKAB9ZCqMrUaWASm1uOggANw0BIXBoABEaSlo5I2QAHgAVAD4pVKgIAA9gCDoAE3IoJTosOgQAdzooAH5pK2zFUI1WCIMoAFU6GgQ6JJMzKVj4mkSxZLsyccYWNw9FVXVNZnTA3n5Fnj0IjgAqA4EoA6gAAQALGiKiwpODjgE8sFNgKC6AfV7+ugB5JDJP45fKFEpQBByABWEAAxsBMugTlAUX8ANqWPB-AC6+yODygqSoRDo5CQphUxDqaLRf2hcOA2OxUHowAQVKgNJ+AyZBPOYCIxMpwLZH2JpPJVBUfKoEGASiopM5aJQdBAvNOFzyRBUYAANhACQADE3AcjGk0PJ4vN4fKI9PoDAFAkEFYqlSEw+GI5Go11g0rlSo1Oi+hpQb6O-6Av7pMOtMJUCKREQAYVMsvhUm50emxFmjnmLnchE83lWLDjOjmTHc5fCKegfwQYFKmEjv2dMwctCLi1Lyx8ayrQTaVCAA