MST
星途 面试题库

面试题:TypeScript下在大型项目中基于问题域语言设计可维护的类型体系

设想一个企业级的项目,涵盖多个业务模块,如订单管理、库存管理、客户关系管理等。不同模块之间存在数据交互和依赖。请阐述如何基于问题域语言,在TypeScript中设计一个统一且可维护的类型体系,确保各个模块之间类型的一致性和扩展性,同时举例说明关键类型的命名和设计思路。
39.4万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

1. 基于问题域语言设计类型体系的总体思路

  • 理解问题域:深入了解订单管理、库存管理、客户关系管理等各业务模块的功能、数据交互和依赖关系。例如,订单管理模块可能依赖库存管理模块的库存数量信息来判断订单是否可发货,依赖客户关系管理模块的客户信息来创建订单。
  • 分层设计:将类型体系分为基础类型层、业务领域类型层和模块交互类型层。
    • 基础类型层:定义一些通用的基础类型,如日期、ID、名称等,这些类型在多个业务模块中可能会被复用。例如:
// 基础类型:日期
type AppDate = string; 
// 基础类型:唯一标识符
type AppId = string; 
// 基础类型:名称
type AppName = string; 
- **业务领域类型层**:根据各业务模块的特点,定义与业务紧密相关的类型。以订单管理模块为例:
// 订单状态枚举
enum OrderStatus {
    Pending = 'pending',
    Processing = 'processing',
    Shipped ='shipped',
    Completed = 'completed',
    Cancelled = 'cancelled'
}

// 订单类型
type Order = {
    orderId: AppId;
    customerId: AppId;
    orderDate: AppDate;
    status: OrderStatus;
    items: OrderItem[];
    totalAmount: number;
};

// 订单项类型
type OrderItem = {
    productId: AppId;
    quantity: number;
    price: number;
};
- **模块交互类型层**:用于定义模块之间交互的数据类型。比如订单管理模块与库存管理模块交互时,可能需要的类型:
// 订单发货请求,包含订单ID和所需库存信息
type OrderShipmentRequest = {
    orderId: AppId;
    items: {
        productId: AppId;
        quantity: number;
    }[];
};
  • 使用接口和类型别名:接口和类型别名在TypeScript中都可用于定义类型,但接口更适合定义对象类型且支持合并,类型别名功能更通用。例如对于订单类型,使用类型别名更简洁,而对于一些可扩展的对象类型,可以使用接口。

2. 确保类型一致性和扩展性的方法

  • 类型共享:通过将基础类型和部分通用业务类型放在共享的模块中,供各个业务模块引用,确保类型一致性。例如上述的 AppDateAppId 等基础类型,可以放在一个 commonTypes.ts 文件中,各个模块都从该文件导入。
  • 利用泛型:在设计可复用的函数或数据结构时,使用泛型来提高扩展性。比如定义一个通用的分页结果类型:
// 通用分页结果类型
type PaginationResult<T> = {
    data: T[];
    total: number;
    page: number;
    pageSize: number;
};

// 假设获取订单列表的分页结果
type OrderPaginationResult = PaginationResult<Order>;
  • 严格类型检查:在项目中开启严格的TypeScript类型检查选项,如 strict: true,确保代码在编译阶段就能发现类型错误,避免运行时错误。

3. 关键类型的命名和设计思路举例

  • 命名思路:关键类型的命名应清晰反映其在问题域中的含义,采用驼峰命名法。例如 OrderStatus 清晰表明是订单的状态类型,OrderShipmentRequest 表明是订单发货请求的类型。
  • 设计思路:以 Customer 类型为例,在客户关系管理模块中:
// 客户类型
type Customer = {
    customerId: AppId;
    name: AppName;
    email: string;
    phone: string;
    address: string;
    // 客户可能有多个联系人
    contacts: Contact[];
};

// 联系人类型
type Contact = {
    contactId: AppId;
    name: AppName;
    email: string;
    phone: string;
};

这里 Customer 类型的设计思路是将客户相关的基本信息以及联系人信息组合在一起,符合客户关系管理的业务逻辑。通过这种方式,既保证了类型的完整性,又便于其他模块(如订单管理模块获取客户信息时)进行复用和交互。