MST

星途 面试题库

面试题:TypeScript 高级类型在复杂项目架构中的设计与优化

假设你正在开发一个大型的 TypeScript 项目,涉及到多个模块和复杂的类型交互。请描述如何利用高级类型(如映射类型、条件类型、类型推断等)来设计一个灵活且可维护的类型架构,以确保不同模块之间的类型兼容性和扩展性。并举例说明在项目中可能遇到的类型难题,以及如何通过高级类型技巧来解决这些问题。
10.6万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

利用高级类型设计灵活且可维护的类型架构

  1. 映射类型
    • 用途:用于基于现有类型创建新类型。例如,当你有一个对象类型,想对其所有属性执行相同操作时,映射类型非常有用。
    • 示例
type User = {
  name: string;
  age: number;
  email: string;
};

// 将User类型的所有属性变为只读
type ReadonlyUser = {
  readonly [P in keyof User]: User[P];
};
  1. 条件类型
    • 用途:根据条件选择不同的类型。在处理联合类型或需要根据某个类型条件进行类型转换时很有用。
    • 示例
type IsString<T> = T extends string? true : false;

type Result = IsString<string>; // true
type AnotherResult = IsString<number>; // false
  1. 类型推断
    • 用途:TypeScript 编译器自动根据上下文推断类型。在函数返回值类型、泛型函数等场景下发挥重要作用,减少显式类型声明,提高代码简洁性。
    • 示例
function add(a: number, b: number) {
  return a + b;
}

let result = add(1, 2); // result类型被推断为number

项目中可能遇到的类型难题及解决方法

  1. 难题:在不同模块中,有一个表示用户信息的对象,但部分模块需要只读版本,部分模块需要可写版本,同时要确保类型一致。
    • 解决方法:使用映射类型。如上述 UserReadonlyUser 的例子,通过映射类型将 User 类型的所有属性变为只读,确保了不同模块对用户信息类型需求的兼容性和扩展性。
  2. 难题:一个函数接收不同类型的参数,根据参数类型返回不同类型的值。例如,传入字符串返回字符串长度,传入数字返回其平方。
    • 解决方法:使用条件类型结合类型推断。
function processValue<T>(value: T): T extends string? number : T extends number? number : never {
  if (typeof value ==='string') {
    return value.length as any;
  } else if (typeof value === 'number') {
    return value * value as any;
  }
  throw new Error('Unsupported type');
}

let strResult = processValue('test'); // strResult类型为number
let numResult = processValue(5); // numResult类型为number
  1. 难题:在一个模块中定义了一个通用的函数,它需要接收不同类型的数组,并对数组中的每个元素执行特定操作,但操作因元素类型而异。
    • 解决方法:结合泛型、条件类型和映射类型。
type StringProcessor = (s: string) => string;
type NumberProcessor = (n: number) => number;

function processArray<T>(arr: T[], processor: T extends string? StringProcessor : T extends number? NumberProcessor : never): (T extends string? string : T extends number? number : never)[] {
  return arr.map((item) => {
    if (typeof item ==='string') {
      return processor(item) as any;
    } else if (typeof item === 'number') {
      return processor(item) as any;
    }
    throw new Error('Unsupported type');
  }) as any;
}

let stringArr = ['a', 'b'];
let processedStringArr = processArray(stringArr, (s) => s.toUpperCase());

let numberArr = [1, 2];
let processedNumberArr = processArray(numberArr, (n) => n * 2);