我是条件类型的新手,所以我尝试了最明显的静态方法,但没有成功:
type NoUnion<Key> =
Key extends 'a' ? 'a' :
Key extends 'b' ? 'b' :
never;
type B = NoUnion<'a'|'b'>;
B型仍然是一个联盟。有人请你上学吗?
这里是playground。
答案 0 :(得分:7)
我不确定这是什么用例,但如果传递的类型是联合类型,我们可以强制NoUnion
到never
。
正如其他提到的条件类型在union上分布一样,这称为distributive conditional types
检查类型是裸类型参数的条件类型称为分布式条件类型。分布式条件类型在实例化期间自动分布在联合类型上。例如,T的实例化扩展了U? X:Y,类型参数为A | B | T的C被解析为(A扩展U?X:Y)| (B扩展U?X:Y)| (C扩展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
取自here
答案 1 :(得分:3)
顺便说一下,&#34;更简单&#34;一个我试图想出来的样子:
type NotAUnion<T> = [T] extends [infer U] ?
U extends any ? [T] extends [U] ? T : never : never : never;
这应该有用(请测试一下;不确定为什么我在my answer to another question错误的原始版本,但它现在已修复)。它与UnionToIntersection
的想法类似:您希望确保T
类型T
可分配给T
的每个部分。一般来说,只有当@Url.Action("ArticleDetails", "Information", new { slug = article.Slug })
是一个只有一个组成部分的联盟时(这也称为&#34;不是联盟&#34;),这是唯一的。
无论如何,@ TitianCernicovaDragomir的答案也完全没问题。只是想在那里得到这个版本。欢呼声。
答案 2 :(得分:1)
这也有效:
type NoUnion<T, U = T> = T extends U ? [U] extends [T] ? T : never : never;