打字稿中管理模型实例化和创建的最佳方法是什么?

时间:2019-03-13 15:38:25

标签: typescript

我一直在尝试用正确的方法在打字稿中实例化和初始化模型。在我的项目中,我使用的是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版本),但是没有发现是一种干净的方法来实现此目的。我有点惊讶,这个基本的东西似乎没有明确的解决方案。 (但也许我只是天真)。

1 个答案:

答案 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
    }

    ....
}
相关问题