Я не уверен, каков вариант использования этого, но мы можем принудительно установить NoUnion
в never
, если переданный тип является типом объединения.
Поскольку другие упомянутые условные типы распространяются по объединению,это называется дистрибутивные условные типы
Условные типы, в которых проверяемый тип является параметром обнаженного типа, называются дистрибутивными условными типами.Распределительные условные типы автоматически распределяются по типам объединения во время реализации.Например, экземпляр T расширяет U?X: Y с аргументом типа A |Б |C для T определяется как (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
взято с здесь