首页 > 解决方案 > 为什么 ts-toolbelt 库使用“O 扩展未知”表达式

问题描述

我正在研究 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

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

标签: typescript

解决方案


据推测,图书馆作者决定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

类似地,_UnionOf不是跨联合分布的(与它在定义中使用的事实有关keyof):

type Oops = _UnionOf<{ a: string } | { b: number }>
// never

如果你有一个在联合中不是分布式的类型函数并且你希望它是,你可以将它包装在一个分布式条件类型中:

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

type UnionKeyofAorB = DistribKeyof<{ a: string } | { b: number }>; // "a" | "b"

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

type Correct = UnionOf<{ a: string } | { b: number }>
// string | number

Playground 代码链接


推荐阅读