MST

星途 面试题库

面试题:TypeScript类型体操之高级类型组合

实现一个TypeScript类型工具`DeepPartial`,它能将一个嵌套对象的所有属性及其子属性都变为可选。例如,对于类型`{ a: { b: number } }`,应用`DeepPartial`后应得到`{ a?: { b?: number } }`。要求使用高级类型如映射类型、递归类型等完成,同时说明实现过程中对各种高级类型概念的运用及可能遇到的边界情况。
34.8万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

实现代码

type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends object
      ? DeepPartial<T[P]>
       : T[P];
};

实现过程中高级类型概念的运用

  1. 映射类型[P in keyof T] 这部分使用了映射类型。它会遍历类型 T 的所有键 P,然后为每个键创建新的属性。这里通过 [P in keyof T]?: 将属性设置为可选。
  2. 条件类型T[P] extends object? DeepPartial<T[P]> : T[P] 使用了条件类型。它判断 T 中属性 P 的类型 T[P] 是否为对象类型。如果是对象类型,则递归应用 DeepPartial 类型工具;如果不是对象类型,则保持原类型。
  3. 递归类型:在条件类型中,当 T[P] 是对象类型时,递归调用 DeepPartial<T[P]>,这使得嵌套对象的所有层级的属性都变为可选。

边界情况

  1. 循环引用:如果对象类型存在循环引用,例如 type Circular = { a: Circular },递归类型会导致无限循环,编译时会报错。实际应用中应避免创建这样的类型。
  2. 特殊类型处理:对于 Function 类型,在上述实现中它不会被当作对象类型递归处理,保持原类型。如果希望对函数类型的参数和返回值也进行类似处理,需要进一步扩展条件类型的判断逻辑。
  3. 泛型约束:若传入的 T 是一个受约束的泛型,例如 T extends { requiredProp: string },在使用 DeepPartial 后,requiredProp 依然会变为可选,可能与预期的部分属性保持必填有所冲突,需额外处理。