MST

星途 面试题库

面试题:TypeScript联合类型的分发与条件类型

已知有一个条件类型`type IsString<T> = T extends string ? true : false;`,以及联合类型`type StringOrNumber = string | number;`。请解释当`IsString<StringOrNumber>`时,TypeScript是如何进行类型分发的,并详细说明这种分发机制在复杂条件类型组合中的应用场景和潜在问题。同时,举例说明如何利用这种分发机制实现一些实用的类型转换。
40.7万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

TypeScript 中类型分发机制解释

  1. IsString<StringOrNumber>的类型分发
    • 当使用IsString<StringOrNumber>时,TypeScript 会对联合类型StringOrNumber(即string | number)进行类型分发。它会将联合类型中的每个成员类型分别代入到条件类型IsString<T>T中进行检查。
    • 对于string,代入IsString<T>后,因为string extends stringtrue,所以IsString<string>的结果是true
    • 对于number,代入IsString<T>后,因为number extends stringfalse,所以IsString<number>的结果是false
    • 最终IsString<StringOrNumber>的结果是true | false,这是对联合类型每个成员类型应用条件类型后的结果的联合。
  2. 分发机制在复杂条件类型组合中的应用场景
    • 类型过滤:可以用来从联合类型中过滤出特定类型。例如,假设有一个联合类型type AllTypes = string | number | boolean,要过滤出字符串类型,可以定义type FilterStrings<T> = T extends string ? T : never,然后FilterStrings<AllTypes>的结果就是string,因为对联合类型中的每个成员应用该条件类型后,只有string类型满足条件被保留,numberboolean类型都变为never,联合后就只剩下string
    • 类型映射:对联合类型中的每个类型进行不同的映射转换。比如,定义type MapToString<T> = T extends string ? str: ${T}: T extends number ?num: ${T} : neverMapToString<AllTypes>的结果就是"str: string" | "num: number",实现了将stringnumber类型映射为不同字符串格式的功能。
  3. 潜在问题
    • 结果类型复杂:当联合类型成员众多且条件类型复杂时,最终结果的联合类型会变得非常复杂,难以理解和维护。例如,如果有一个包含 10 种不同类型的联合类型,并且每个类型在条件类型中有复杂的逻辑判断,那么最终的结果联合类型会有很多成员,阅读和调试都变得困难。
    • 分发与非分发的混淆:在编写复杂条件类型时,很容易混淆分发和非分发的情况。例如,在条件类型中使用了一些会阻止分发的操作(如使用Exclude等工具类型),可能导致预期的分发行为不发生,从而得到错误的结果。

利用分发机制实现实用的类型转换示例

  1. 提取联合类型中的字符串类型
type IsString<T> = T extends string? T : never;
type StringOrNumber = string | number;
type OnlyStrings = IsString<StringOrNumber>; // 结果为 string
  1. 将联合类型中的数字类型转换为字符串类型
type ToString<T> = T extends number? string : T;
type StringOrNumber = string | number;
type Converted = ToString<StringOrNumber>; // 结果为 string | string,可简化为 string