TypeScript开发Node.js通用控制器时遇到CreateEntityDto类型用作值的错误求助
TypeScript开发Node.js通用控制器时遇到CreateEntityDto类型用作值的错误求助
嘿,我懂你想做通用控制器的诉求——重复写相似的CRUD代码确实够折腾的。从你贴的CompanyController代码来看,它能正常运行,但改成通用版本时大概率踩了「把TypeScript类型当成运行时值来用」的坑,毕竟TypeScript类型在编译后就会被擦除,像CreateEntityDto这种类型没法直接传给plainToInstance这类需要运行时构造函数的方法。
我给你整理了一个可行的通用控制器实现思路,你可以参考:
首先,定义一个泛型的通用控制器基类,同时要把Dto的构造函数作为依赖传入(因为运行时必须拿到它才能实例化对象):
import { Request, Response } from 'express'; import { plainToInstance } from 'class-transformer'; import { BaseService } from './base.service'; // 假设你有封装好的基础服务类 export class GenericController<T, CreateDto, ReturnDto> { constructor( private service: BaseService<T, CreateDto, ReturnDto>, private createDtoConstructor: new () => CreateDto, // 传入CreateDto的构造函数 private returnDtoConstructor: new () => ReturnDto // 传入返回Dto的构造函数 ) {} async create(req: Request, res: Response): Promise<ReturnDto> { // 这里用传入的构造函数,而非TypeScript类型 const createDto = plainToInstance(this.createDtoConstructor, req.body); const entity = await this.service.create(createDto); return plainToInstance(this.returnDtoConstructor, entity); } // 你还可以继续扩展getAll、getById、update、delete这类通用CRUD方法 }
然后,你的CompanyController就可以直接继承这个基类,传入对应的构造函数即可:
import { CompanyService } from './company.service'; import { CreateCompanyDto } from './dto/create-company.dto'; import { CompanyDto } from './dto/company.dto'; import { GenericController } from './generic.controller'; export class CompanyController extends GenericController< Company, // 你的实体类型 CreateCompanyDto, CompanyDto > { constructor(companyService: CompanyService) { super(companyService, CreateCompanyDto, CompanyDto); } }
这里的核心是分清TypeScript类型和运行时的值:
CreateCompanyDto作为类型时,只是编译阶段的约束;- 但
plainToInstance需要的是一个能实例化对象的构造函数(也就是new () => CreateCompanyDto类型的值),所以必须在通用控制器的构造函数里传入这个构造函数,不能直接用类型。
另外,你的基础服务类(BaseService)也建议做成泛型的,这样通用控制器才能和它无缝配合,比如让BaseService的create方法接收CreateDto类型的参数,返回实体对象。
要是你还有具体的错误信息或者未贴全的代码片段,可以补充出来,我再帮你细化解决~
备注:内容来源于stack exchange,提问作者derstauner
相关产品推荐
相关产品推荐

