如何从工厂函数获取类类型为NestJS动态控制器指定TypeScript类型?
解决NestJS动态控制器工厂函数的TypeScript类型推断问题
可以通过优化工厂函数的类型定义和控制器生成逻辑的泛型约束,让TypeScript正确推断出动态生成的DTO类类型,避免出现any。以下是具体解决方案:
1. 修正统一DTO工厂的类型定义
首先明确类构造函数的泛型类型,优化工厂函数的条件返回类型,让TypeScript能准确追踪不同操作对应的返回类型:
// 定义带泛型的类构造函数类型 type ClassConstructor<T = any> = new (...args: any[]) => T; // 模拟原统一响应DTO包装函数(根据实际逻辑调整) function UniformResponseDto<T extends ClassConstructor>(DTO: T) { class WrappedDTO { data!: InstanceType<T>; } return WrappedDTO; } // 优化后的条件返回类型 type ConditionalReturnType<T extends ClassConstructor | ClassConstructor[], O extends string> = O extends 'list' ? T extends ClassConstructor[] ? Array<InstanceType<T[number]>> : never // 列表场景强制要求传入数组形式的DTO : ReturnType<typeof UniformResponseDto<T extends ClassConstructor ? T : never>>; // 修正后的工厂函数 function factory<T extends ClassConstructor | ClassConstructor[], O extends string>( DTO: T, op: O ): ConditionalReturnType<T, O> { if (op === 'list') { return DTO as ConditionalReturnType<T, O>; } return UniformResponseDto(DTO as ClassConstructor) as ConditionalReturnType<T, O>; }
2. 优化动态控制器生成函数
将工厂函数的类型约束从宽泛的any改为具体的typeof factory,让TypeScript能正确推断生成的DTO类类型:
function createController<ModelDTOType extends ClassConstructor>( ModelDTO: ModelDTOType, uniformDTOFactory: typeof factory ) { // 现在TypeScript能正确推断这两个变量的类型,不再是any const RetrieveDTO = uniformDTOFactory(ModelDTO, 'retrieve'); const ListDTO = uniformDTOFactory([ModelDTO], 'list'); type RetrieveDTOType = InstanceType<typeof RetrieveDTO>; type ListDTOType = InstanceType<typeof ListDTO>; class DynamicController { async list(): Promise<ListDTOType> { return [{ id: 1 }] as ListDTOType; } async retrieve(): Promise<RetrieveDTOType> { return { data: { id: 1 } } as RetrieveDTOType; } } return DynamicController; }
关键修改说明
- 给
ClassConstructor添加泛型参数,明确类的实例类型,为后续类型推断提供基础 - 优化
ConditionalReturnType,区分列表/单条数据场景的返回类型,让TypeScript能精准识别 - 控制器生成函数中,将
uniformDTOFactory的类型绑定到具体的factory函数类型,避免泛型丢失导致的any推断 - 简化控制器函数的泛型参数,去掉不必要的抽象约束,提升类型推断的准确性
经过上述调整,RetrieveDTOType和ListDTOType会被正确推断为对应的类实例类型,控制器方法的返回类型也会受到TypeScript的类型校验,不再是any。
内容的提问来源于stack exchange,提问作者Felipe Buccioni
相关产品推荐
相关产品推荐

