01097-medium-isunion

Back

// 你的答案
type IsUnion<T, U = T> = [T] extends [never] ? false : T extends U ? [U] extends [T] ? false:  true : false;

Solution by HelloGGG #33423

// your answers
type IsUnion<T, K = T> = [T] extends [never]
  ? false
  : K extends K
    ? [T] extends [K]
      ? false
      : true
    : never

Solution by pea-sys #32610

type IsUnion<T, C = T> = 
  (T extends unknown 
    ? C extends T 
      ? true
      : false
    : never) extends true ? false : true

분배법칙이 일어났을 때의 T와 정적으로 C가 가지고 있는 타입의 관계를 비교하여 Union인지 아닌지를 체크할 수 있다.

Solution by dev-hobin #32422

type IsUnion<T, K = T> = [T] extends [never]
  ? false
  : K extends K
    ? [T] extends [K]
      ? false
      : true
    : never

Solution by yoonnokdoo #32395

type IsUnion<T, S = T> = [T] extends [never]
  ? false
  : S extends S
    ? Equal<T, S> extends true
      ? false
      : true
    : never
type IsUnion<T, S = T> = [T] extends [never]
  ? false
  : S extends S
    ? NotEqual<T, S>
    : never

Solution by Heonys #32100

// your answers
// 使用 296 的 Permutation,得出笛卡尔乘积组合解决
type Permutation<T, U extends T = T> = [T] extends [never]
  ? []
  : U extends U
  ? [U, ...Permutation<Exclude<T, U>>]
  : never;
type IsUnion<T> = Permutation<T>['length'] extends (0 | 1) ? false : true;

Solution by wenxiangdong #31760

type IsUnion<T, U = T> = [T] extends [never] 
  ? false 
  : T extends infer V 
    ? [Exclude<U, V>] extends [never] ? false : true
    : never

Solution by kai-phan #31667


type IsUnion<T> = { [K in T as T extends K ? 'false' : 'true']: true } extends { true: true } ? true : false;

Basic idea: match every member in a union against everything and map this to a mapped type with "true"/"false" keys, then try to match for "true" key.

PS: I'm not sure if I used the correct language or if I properly understood how everything works.

Solution by tany1 #31604

type IsUnion<T, B = T> = [T] extends [never]
  ? false
  : T extends B
  ? [B] extends [T]
    ? false
    : true
  : never;

Solution by vipulpathak113 #31538

With NotEqual.

// your answers
type IsUnion<T> = NotEqual<[T] & T, (T extends T ? [T] : never) & T>; 

Solution by sugoroku-y #31477

Referenced Equal.

// your answers
type IsUnion<T> = (
    T extends T ? <S>() => S extends T ? 1 : 2 : never
) extends <S>() => S extends T ? 1 : 2
    ? false
    : true;

@doox911-opensource commented

I think this is the best solution. And great explanation.

But the test:

  Expect<Equal<IsUnion<(() => any)|(() => 15)>, true >>,

failed

This test case has also been successful.

Playground

Solution by sugoroku-y #31295

type IsUnionImpl<T, C extends T = T> = (T extends T ? C extends T ? true : unknown : never) extends true ? false : true;
type IsUnion<T> = IsUnionImpl<T>;

Solution by MyeonghoonNam #30992

type IsUnion<T, K = T> = 
  [T] extends [never]
    ? false
    : K extends K
      ? [Exclude<T, K>] extends [never]
        ? false
        : true
      : false;

Solution by vprokashev #30955

// your answers
type UnionToArray<T> = T extends T ? Array<T> : never
type IsUnion<T> = [T] extends [never] ? false : Array<T> extends UnionToArray<T> ? false : true

Solution by yangdonglai #30722

type IsUnion<T, R = T> = [T] extends [never] ? false : (T extends any ? ([Exclude<R, T>] extends [never] ? false : true) : true);

Solution by kai-phan #30391

Implementation

export type IsUnion<U> = _IsUnionImpl<U, U>;

/** @internal */
type _IsUnionImpl<U, K extends U> = IsNever<U> extends true
  ? false
  : K extends K
  ? BoolNot<TypeEq<U, K>>
  : never;

type IsNever<T> = [T] extends [never] ? true : false;

// https://github.com/microsoft/TypeScript/issues/27024
type TypeEq<A, B> =
  (<T>() => T extends A ? 1 : 2) extends
  (<T>() => T extends B ? 1 : 2)
    ? true
    : false;

type BoolNot<A extends boolean> =
  TypeEq<A, true> extends true
    ? false
    : TypeEq<A, false> extends true
    ? true
    : never;

Test

/**
 * @param _relation `"=" | "<=" | "!="`
 * @description
 * - `expectType<A, B>("=")` passes if `A` is equal to `B`.
 * - `expectType<A, B>("<=")` passes if `A` extends `B`.
 * - `expectType<A, B>("!=")` passes if `A` is not equal to `B`.
 */
const expectType = <A, B>(
  _relation: TypeEq<A, B> extends true
    ? '<=' | '='
    : TypeExtends<A, B> extends true
    ? '!=' | '<='
    : '!<=' | '!='
): void => undefined;

expectType<IsUnion<never>, false>('=');
expectType<IsUnion<string>, false>('=');
expectType<IsUnion<number | string>, true>('=');
expectType<IsUnion<[number | string]>, false>('=');

expectType<
  IsUnion<Readonly<{ a: 0 }> | Readonly<{ a: 1; b: 1 }> | Readonly<{ b: 2 }>>,
  true
>('=');

expectType<IsUnion<Record<number, number> | Record<string, number>>, true>('=');

expectType<
  IsUnion<
    | Readonly<{ a: 0 }>
    | Readonly<{ a: 1; b: 1 }>
    | Readonly<{ b: 2 }>
    | Record<string, number>
  >,
  true
>('=');

Description

WIP

Solution by noshiro-pf #29976

type IsUnionImpl<T, C extends T = T> =
  (T extends infer TItem // Iterate over T, here TItem is an item from the original union T. Ingredients 1&2
    ? C extends TItem // C holds the original union T. Does union T extends an item from it? // Ingredient 3
      ? true // yes. that could only be true if union T consist of one item
      : false // no
    : never) extends true ? false : true // have we got true from the above? yes - it's not a union

type IsUnion<T> = IsUnionImpl<T>

Solution by qianzhong516 #29913

type IsUnion<T, U = T> = [T] extends [never] ? false : T extends U ? IsUnion<Exclude<U, T>, T> : true

Solution by Yirujet #29539

// your answers

type IsUnion<T> = HasMoreThanOnePermutation<T>;

type Permutation<T, acc extends any[] = [], ALL = T> = [T] extends [never]
  ? acc
  : T extends T
  ? Permutation<Exclude<ALL, T | acc[number]>, [...acc, T], ALL>
  : acc;

type HasMoreThanOnePermutation<T extends any> = Permutation<T> extends [
  infer U,
  ...infer R
]
  ? [U] extends [never] // size 0
    ? false
    : R extends never[] // size 1
    ? false
    : true //more than 1 permutation
  : false; // should never happen

image

Solution by lamine-ndouop-deel #29422

type IsUnion<T, U = T> =[T] extends [never] ? false : T extends U ? [U] extends [T] ? false : true : never

Solution by IvanKoigerov #28884

type IsNever<T> = [T] extends [never] ? true : false;
type IsUnion<T, I = T> = IsNever<T> extends true ? false : (T extends I ? [I] extends [T] ? false : true : false)

Solution by hajeonghun #28759

type IsEqual<A, B> = (() => T extends A ? 1 : 2) extends () => T extends B ? 1 : 2 ? true : false;

type IsUnion<T, U = T> = [T] extends [never] ? false : T extends U ? IsEqual<T, U> extends true ? false : true : never;

Solution by DoubleWoodLin #28643

// your answers
type IsUnion<T, B = T> = [T] extends [never] ? false : T extends B ? [B] extends [T] ? false : true : never;

Solution by ixiaolong2023 #27786

type IsUnion<T, C = T> = [T] extends [never]
  ? false
  : C extends C
  ? [Exclude<T, C>] extends [never]
    ? false
    : true
  : never;

Solution by idebbarh #27600

type IsUnion<T, B = T> = T extends B ? [T] extends [B] ? false : true : never;

Solution by vuongManabie #26846

type IsUnion<T, U = T> = (T extends T ? U extends T ? true : unknown : never) extends true ? false : true

思路:

  1. T extends T可以判断T是否为never;
  2. U extends T,extends可以拆分联合类型分别判断,再将每个子结果再联合起来;
  3. 如果T是联合类型,那么子结果就会含有unknown ,括号最终的结果是一个含有unknown的联合类型;
  4. Union extends true,Union含有unknown就是一个联合类型,只含有never或true就不是一个联合类型,可以通过extends true来判断。

Solution by smileboyi #26845

type IsUnion<T, B = T> = [T] extends [never] 
? false
: T extends B 
  ? [B] extends [T] 
    ? false : true 
  : false

Solution by avatar0813 #26737

type IsUnion<T, K = T> = [T] extends [never] ? false : T extends K ? ([K] extends [T] ? false : true) : never;

Solution by 8471919 #26701

type IsUnion<T, B = T> =  [T] extends [never] ? false : T extends B ?  [B] extends [T] ? false : true : false; 

Solution by AwesomeYelim #26592

type IsPartitionSameEntire<T, P = T> = T extends P ? P extends T ? false : true : false;
type IsUnion<T> = IsPartitionSameEntire<T> extends true ? false : IsPartitionSameEntire<T> extends false ? false : true;

Solution by kakasoo #26326