我对条件类型还不熟悉,所以我尝试了最显然的静态方式,但没有成功:
type NoUnion<Key> =
Key extends 'a' ? 'a' :
Key extends 'b' ? 'b' :
never;
type B = NoUnion<'a'|'b'>;
B类型仍然是union(联合)。请有人给我讲解一下?
这里有一个playground。
我对条件类型还不熟悉,所以我尝试了最显然的静态方式,但没有成功:
type NoUnion<Key> =
Key extends 'a' ? 'a' :
Key extends 'b' ? 'b' :
never;
type B = NoUnion<'a'|'b'>;
B类型仍然是union(联合)。请有人给我讲解一下?
这里有一个playground。
我不确定这个用例是什么,但如果传递的类型是联合类型,我们可以强制 NoUnion
为 never
。
正如其他人提到的条件类型分布在联合类型之上,这被称为分布式条件类型
检查的类型为裸类型参数的条件类型被称为分布式条件类型。在实例化期间,分布式条件类型会自动分布在联合类型上。例如,T extends U? X: Y 的实例化类型参数为 A | B | C,则该类型将被解析为 (A extends U? X: Y) | (B extends U? X: Y) | (C extends U? X: Y)。
关键在于“裸类型”,例如,如果我们将类型包装在元组类型中,那么条件类型将不再是分布式的。
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type NoUnion<Key> =
// If this is a simple type UnionToIntersection<Key> will be the same type, otherwise it will an intersection of all types in the union and probably will not extend `Key`
[Key] extends [UnionToIntersection<Key>] ? Key : never;
type A = NoUnion<'a'|'b'>; // never
type B = NoUnion<'a'>; // a
type OtherUnion = NoUnion<string | number>; // never
type OtherType = NoUnion<number>; // number
type OtherBoolean = NoUnion<boolean>; // never since boolean is just true|false
boolean
视为true | false
,所以NoUnion<boolean>
实际上将是never
。如果没有更多关于你想要实现的具体细节,很难知道这是否是一个致命问题,但可以通过将boolean
视为特殊情况来解决:type NoUnion<Key> =
[Key] extends [boolean] ? boolean :
[Key] extends [UnionToIntersection<Key>] ? Key : never;
UnionToIntersection
是从这里引用的。Error:(26, 10) TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((arg: Command<"a">) => number) | ((arg: Command<"b">) => string)' has no compatible call signatures.
如果你将在 JSBin 中的代码片段粘贴到 TS Playground 中,则应该会看到此问题。感谢您的帮助,抱歉没有详细说明。 - Daniel Birowsky Popeski// type NotAUnion<T> = [T] extends [infer U] ?
// U extends any ? [T] extends [U] ? T : never : never : never;
目前至少在分发之前,可以使用以下内容,因为默认值仍会被实例化:
type NotAUnion<T, U = T> =
U extends any ? [T] extends [U] ? T : never : never;
我希望这个可以工作(请测试一下;不确定为什么我在回答另一个问题中得到了原始版本,但现在已经修复)。这是与UnionToIntersection
类似的想法:如果您分配它,则要确保类型T
可分配给T
的每个部分。一般来说,只有当T
是具有一个组成部分的联合体时(也称为“非联合”)才成立。
无论如何,@TitianCernicovaDragomir的回答也完全可以。只是想让这个版本出现。干杯。
[T]
中的括号只用于元组,但在这里似乎有其他语义。您能澄清一下吗?(提供资源链接也可以) - Daniel Birowsky PopeskiT
是一个“裸类型参数”,则 T extends U ? X : Y
会进行分发。其思想是要将其“包装”:仅当 T extends U
(因为单元素元组在它们的类型中是协变的),才应该保持 [T] extends [U]
,但防止分发 T
。这里使用元组语法并没有什么特别之处;任何协变类型都可以:{x: T} extends {x: U}
仅当 T extends U
时成立。但 [T]
可能是最简短的方法。 - jcalz3.3.3
(我在 playground 中测试的最后一个版本)中它不起作用。您可以将 3.3.3
与 3.5.1
进行比较。似乎无法再将推断类型参数 U
裸露出来以创建分布式联合类型 - 对我来说听起来像是一个 bug。 - ford04这也是有效的:
type NoUnion<T, U = T> = T extends U ? [U] extends [T] ? T : never : never;
B
是什么? - Asad Saeeduddinnever
。在实际使用中,则使用'a'
或'b'
。 - Daniel Birowsky PopeskiNoUnion
中的两种条件类型,因此最终得到了a|b
。当第一个条件通过时,条件类型并不会停止。 - Fenton