编程前端开发人员

什么是 TypeScript 中的分布式类型 (Distributive Types),它们的应用场景以及在使用时需要考虑的特点是什么?

用 Hintsage AI 助手通过面试

答案

分布式类型 (Distributive Types) 是 TypeScript 的一个特性,体现在条件类型 (T extends U ? X : Y) 的使用上。当 extends 左侧的类型变量是一个联合类型时,TypeScript 会将条件应用于联合中的每个元素。

示例:

// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;

这里 Result 将分布为:

  • Test<'A'> | Test<'B'> | Test<'C'>

应用场景 — 用于编写通用 API、对联合类型进行操作,例如过滤或模式匹配。

特点:

  • 如果将 T 包裹在元组 [T] 中,则不会发生分布。这是一种“禁用”分布的方法。
  • 分布仅适用于类型变量(而非字面量)。

易错问题

问题: 类型 T[] extends number[] ? true : false 会是分布式的吗?

正确答案: 不会,分布仅发生在左侧的类型变量没有被数组或元组包裹的情况下。例如,条件类型 T extends number ? ... 会进行分布,但 T[] extends number[] ? ... 则不会。


由于不了解该主题的细节而导致的实际错误示例


故事

项目: 一个用于验证 React 组件的 props 的库。希望实现一个将 union props 转换为严格接口的类型,但因为不理解分布,导致类型变得出乎意料的复杂(union 成员的属性混合在一起)。最后通过添加包裹 [T] 来修正,使分布不再发生。


故事

项目: 将所有事件类型设计为一个函数处理程序。在条件类型中,期望函数能通过分布接收每种事件类型,但由于未显式使用导致处理不正确,导致参数类型错误(使用了 union 而不是每种类型单独调用)。


故事

项目: 在创建自定义工具类型(如 Exclude、Extract)时忘记了对于元组和数组不会发生分布。结果,Exclude 类型在数组中不起作用(例如,类型 Exclude<["a"|"b"], "b"> 不会删除 "b")。