IsUnion
问题描述
实现一个类型 IsUnion,该类型接受输入类型 T 并返回 T是否解析为联合类型。
举例:
type case1 = IsUnion<string> // false
type case2 = IsUnion<string | number> // true
type case3 = IsUnion<[string | number]> // false
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'
type cases = [
Expect<Equal<IsUnion<string>, false>>,
Expect<Equal<IsUnion<string | number>, true>>,
Expect<Equal<IsUnion<'a' | 'b' | 'c' | 'd'>, true>>,
Expect<Equal<IsUnion<undefined | null | void | ''>, true>>,
Expect<Equal<IsUnion<{ a: string } | { a: number }>, true>>,
Expect<Equal<IsUnion<{ a: string | number }>, false>>,
Expect<Equal<IsUnion<[string | number]>, false>>,
// Cases where T resolves to a non-union type.
Expect<Equal<IsUnion<string | never>, false>>,
Expect<Equal<IsUnion<string | unknown>, false>>,
Expect<Equal<IsUnion<string | any>, false>>,
Expect<Equal<IsUnion<string | 'a'>, false>>,
Expect<Equal<IsUnion<never>, false>>
]
// ============= Your Code Here =============
type IsUnion<T, C extends T = T> = (T extends T ? (C extends T ? true : unknown) : never) extends true ? false : true
-
外层条件类型:
(T extends T ? (C extends T ? true : unknown) : never) extends trueT extends T ? ... : ...是一个分布式条件类型,当T是联合类型时,这个条件会对联合类型的每个成员进行检查。- 假设
T = A | B,那么(A | B) extends (A | B)会被分解成A extends (A | B) ? (B extends (A | B) ? true : unknown) : never和B extends (A | B) ? (A extends (A | B) ? true : unknown) : never。 - 如果
T不是联合类型(例如是单个类型),那么T只有一个成员,T extends T => true,
-
内层条件类型:
(C extends T ? true : unknown)C是T的一个扩展类型,并且默认为T本身。因为C也是T的成员之一,所以这一步也会对联合类型的每个成员进行检查。- 对于联合类型的每个成员,检查
C extends T ? true : unknown会产生true或unknown, 最终结果(true | unknown)不能扩展true。 - 如果
T不是联合类型(例如是单个类型),那么T只有一个成员,C extends T => true。
- 因此,如果
T是联合类型,上述外层条件的结果将是true,反之是false。
最终,这个类型的判断逻辑如下:
- 如果结果为
true,表示T不是联合类型。 - 如果结果不是
true,表示T是联合类型。