我一直在尝试用正确的方法在打字稿中实例化和初始化模型。在我的项目中,我使用的是Nest,通过API通过将对象转换为DTO进行验证来获取对象,然后应使用DTO创建模型的实例。
我相信标准方法是这样的:
class myModel {
public constructor (public property: string) {
}
}
class MyModelDto {
public property: string;
}
// instantiation function, the input would come from an http post body:
public function createMyModel(bodyData: MyModelDto) {
const myModel = new MyModel(bodyData.property);
}
好处是,它将永远不会创建具有错误属性的myModel实例化,因为它们都是必需的,并且您无法将额外的属性传递给模型。 但是,问题在于您必须在模型的每个实例中添加完整列表。带有一些属性就可以了,但是一旦您引入多个(10+),就会有点乏味。同样因为顺序很重要,所以冒着将错误数据输入错误属性的风险。只要类型相同,编译器就不会抱怨。
因此,另一种选择是:
class myModel {
public property: string
public constructor (data: myModelInterface) {
Object.assign(this, data)
}
}
interface myModelInterface {
property: string;
}
class MyModelDto {
public property: string;
}
// instantiation function, the input would come from an http post body:
public function createMyModel(bodyData: MyModelDto) {
const myModel = new MyModel(bodyData);
}
这在实例化方面已经很干净了。即使您必须两次拥有相同的属性列表(模型和接口),也永远不会超过2个。
这是我的偏爱,但其缺点是,如果您从MyModelDto定义中省略了属性,则编译器只会告诉您bodyData是错误的,但是如果您添加了额外的属性,它将不会抱怨,也不会省略const myModel
中的数据。有效地抵消了许多打字稿的好处。
如果Obect.assign
仅采用MyModel
类中指定的属性,或者myModel接口将抱怨输入和接口之间的任何差异,而不只是抱怨某个属性,那将是很好的选择不在那里。但我认为这不是javascript的工作方式。
我尝试了其他一些选项(创建自己的Object.assign版本),但是没有发现是一种干净的方法来实现此目的。我有点惊讶,这个基本的东西似乎没有明确的解决方案。 (但也许我只是天真)。
答案 0 :(得分:1)
当我必须在某些数据的两个不同表示形式之间转换时,我首先使用泛型创建一个接口,该接口表示两个表示形式之间的映射器:
export interface IMapper<T, R> {
toDTO(model: T): R;
toModel(dto: R): T;
}
然后在toDTO和toModel方法的实现中,我管理两个类之间的信息映射:
class MyMapper implements IMapper<MyModel, MyModelDTO> {
public toDTO(model: MyModel) {
let dto = new MyModelDTO(....);
// map model infos to dto
....
returFor the convertion sometimes I n dto;
}
public toModel(dto: MyModelDTO) {
let model = new MyModel(....);
// map dto infos to model
....
return model;
}
}
转换视情况而定。
有时可能很简单,例如:
for (let prop in model) {
if (dto[prop]) {
dto[prop] = model[prop]
}
}
在其他情况下,我使用对象来辅助将模型的属性映射到dto的属性,例如:
class MyMapper implements IMapper<MyModel, MyModelDTO> {
private readonly modelToDto = {foo: 'property1', bar: 'prop2'};
public toDTO(model: MyModel) {
let dto = new MyModelDTO(....);
Object.keys(this.fields).forEach((k) => {
dto[this.fields[k]] = model[k];
});
return dto
}
....
}