Есть ли способ предотвратить объединение типов в TypeScript? - PullRequest
0 голосов
/ 01 июня 2018

Я новичок в условных типах, поэтому я попробовал самый очевидный статический способ, но безуспешно:

type NoUnion<Key> =
  Key extends 'a' ? 'a' :
  Key extends 'b' ? 'b' :
  never;

type B = NoUnion<'a'|'b'>;

Тип B все еще является объединением.Кто-нибудь, пожалуйста, обучите меня?

Вот детская площадка .

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Кстати, «более простой» вариант, который я пытался придумать, выглядит следующим образом:

type NotAUnion<T> = [T] extends [infer U] ? 
  U extends any ? [T] extends [U] ? T : never : never : never;

Это должно сработать (пожалуйста, проверьте его; не знаете, почему я получил оригинальную версию в мой ответ на другой вопрос неправильный, но он исправлен).Эта идея похожа на UnionToIntersection: вы хотите убедиться, что тип T назначается каждой части T, если вы распространяете ее.В общем случае это верно только в том случае, если T является объединением только с одной составной частью (которая также называется "не объединением").

Во всяком случае, ответ @ TitianCernicovaDragomir также вполне приемлем.Просто хотел получить эту версию там.Приветствия.

0 голосов
/ 01 июня 2018

Я не уверен, каков вариант использования этого, но мы можем принудительно установить 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 взято с здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...