MST

星途 面试题库

面试题:TypeScript 条件类型的复杂应用

实现一个 TypeScript 类型工具 `IfEquals<A, B, X, Y>`,它接受四个类型参数。当 `A` 和 `B` 严格相等时,返回 `X` 类型,否则返回 `Y` 类型。请详细解释你的实现思路,并且说明在条件类型中如何处理类型递归以及类型分发的原理。
15.1万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试
  1. 实现 IfEquals 类型工具

    type IfEquals<A, B, X, Y> = (<T>() => T extends A? 1 : 2) extends (<T>() => T extends B? 1 : 2)? X : Y;
    
  2. 实现思路解释

    • 这里利用了条件类型中函数类型的比较。
    • 首先创建了两个函数类型 <T>() => T extends A? 1 : 2<T>() => T extends B? 1 : 2
    • AB 严格相等时,对于任何 TT extends AT extends B 的结果是一样的,所以这两个函数类型是相等的。
    • 当这两个函数类型相等时,整个 IfEquals 类型就返回 X,否则返回 Y
  3. 类型递归处理原理

    • 在 TypeScript 中,类型递归通常用于处理复杂的类型结构。例如,在处理链表、树等递归数据结构的类型定义时会用到。
    • 假设我们有一个链表节点类型定义:
    type ListNode<T> = {
        value: T;
        next: ListNode<T> | null;
    };
    
    • 这里 ListNode<T> 类型中,next 字段又引用了 ListNode<T> 自身,这就是一种类型递归。在解析这种类型时,TypeScript 编译器会按照一定规则逐步展开和检查类型,直到满足终止条件(比如 nextnull)。
    • 类型递归需要注意避免无限循环,通常要有一个明确的终止条件。比如在链表中,nextnull 就是终止条件。
  4. 类型分发原理

    • 类型分发主要发生在条件类型中,当条件类型的判断类型是一个泛型时,并且这个泛型是裸类型(没有被包裹在其他类型中)。
    • 例如,type Distribute<T> = T extends string? string literal:not string;
    • 如果我们使用 Distribute<string | number>,它会被分发为 (string extends string? string literal:not string) | (number extends string? string literal:not string),即 string literal | not string
    • 这使得条件类型可以对联合类型中的每个成员分别进行判断,从而实现灵活的类型转换和推导。

    总结来说,类型递归用于处理自引用的复杂类型结构,而类型分发则是条件类型对联合类型的一种特殊处理方式,两者在 TypeScript 的类型系统中都起着重要作用。