为什么 ts-toolbelt 库使用“Oextendsunknown”表达式

Ale*_*kin 4 typescript

我正在研究 ts-toolbelt 库的源代码。而我也经常遇到这样的表情O extends unknown。在我看来,它没有添加任何功能。

所以我想知道,它是做什么用的?

/**
 * @hidden
 */
export type _UnionOf<O extends object> =
    O[keyof O]

/**
 * Transform an [[Object]] into an [[Union]]
 * @param O to transform
 * @returns [[Any]]
 * @example
 * ```ts
 * ```
 */
export type UnionOf<O extends object> =
    O extends unknown
    ? _UnionOf<O>
    : never
Run Code Online (Sandbox Code Playgroud)

由于某种原因,不是导出_UnionOf类型,而是在其前面加上表达式O extends unknown

jca*_*alz 5

据推测,库作者认为UnionOf<A | B | C>应该产生与 相同的结果UnionOf<A> | UnionOf<B> | UnionOf<C>,而 的定义_UnionOf并没有这样做。O extends unknown ? ... : never看似没有任何作用的支票却导致了这种情况的发生。

T当是泛型类型参数时,表达式看起来什么也不做,但实际上分布在联合中:

  • T extends unknown ? ... : never
  • T extends any ? ... : never
  • T extends T ? ... : never

如果T类型参数,如在泛型函数function foo<T>(/*...*/): void或泛型接口中interface Foo<T> {/*...*/},则该形式的类型T extends XXX ? YYY : ZZZ分配条件类型

它将条件检查分布. TT使用某些特定类型指定时,编译器会将该类型拆分为其联合成员,评估每个此类成员的检查,然后将结果连接回新的联合。因此,如果F<T>跨联合分布,则F<A | B | C>与 相同F<A> | F<B> | F<C>


并非所有类型函数都可以跨联合分配。例如,运算keyof不会将输入的并集转换为输出的并集:

type KeyofA = keyof {a: string}; // "a"
type KeyofB = keyof {b: number}; // "b"
type KeyofAorB = keyof ({ a: string } | { b: number }); // never
Run Code Online (Sandbox Code Playgroud)

同样,在联合体之间不具有分配性(与它在定义中_UnionOf使用的事实有关):keyof

type Oops = _UnionOf<{ a: string } | { b: number }>
// never
Run Code Online (Sandbox Code Playgroud)

如果您有一个在联合中具有分配性的类型函数,而您希望它具有分配性,则可以将其包装在分配性条件类型中:

type DistribKeyof<T> = T extends unknown ? keyof T : never;

type UnionKeyofAorB = DistribKeyof<{ a: string } | { b: number }>; // "a" | "b"
Run Code Online (Sandbox Code Playgroud)

因此在工会之间UnionOf 分布式的:

type Correct = UnionOf<{ a: string } | { b: number }>
// string | number
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接