💻

AutoMapper TypeScript を使ってみる

2022/11/04に公開

はじめに

TypeScript のインターフェイスはちょっと曲者で、JavaScript にトランスパイルしたときに型情報は消えてしまうため、実行時にたとえば JSON を読み込んだときに型の不一致を起こしてエラーになることがあります。日付型を読み込んだつもりなのに文字列型になっているのはあるあるですね。日付型は Date として扱いたいので、読み込んだ JSON を変換する処理を入れる必要があるのですが、データのコピーを実装するのはなかなか面倒です。C# でいうところの AutoMapper があればいいのにと思ったらちゃんとありました。

https://automapperts.netlify.app/

AutoMapper TypeScript にはコア ライブラリとストラテジーと呼ばれる機能ごとのライブラリにわかれています。インターフェイスの変換に使用するのは @automapper/pojos になります。

実行方法

インストール

npm からパッケージをインストールします。

npm install @automapper/core @automapper/pojos

インターフェイスの定義

REST API などで外部から以下のような JSON を取得できるとします。

const json = {
  id: 'a84f3c66-25cf-44dd-8dc9-38f89c4d84b2',
  name: 'Hikaru Aizawa',
  createdAt: '2000-01-01T00:00:00Z',
  updatedAt: '2022-11-04T00:00:00Z'
};

この JSON に対応する UserDTO というインターフェイスを定義します。

interface UserDTO {
  id?: string,
  name?: string,
  createdAt?: string,
  updatedAt?: string,
}

ビジネス エンティティとして扱うためのインターフェイスを定義します。createdAtupdatedAt が日付型になっています。

interface User {
  id?: string,
  name?: string,
  createdAt?: Date,
  updatedAt?: Date,
}

メタデータの定義

先にも述べた通りインターフェイスの情報は JavaScript にしたときに消えてしまうのでメタデータとして型情報を定義してあげる必要があります。

PojosMetadataMap.create<UserDTO>('UserDTO', {
  id: String,
  name: String,
  createdAt: String,
  updatedAt: String
});

PojosMetadataMap.create<User>('User', {
  id: String,
  name: String,
  createdAt: Date,
  updatedAt: Date
});

マッパーの作成

ストラテジーに pojos を指定してマッパーを作成します。

const mapper = createMapper({
  strategyInitializer: pojos(),
});

UserDTO から User へのマッピングを定義します。マッピングの方法は本家の AutoMapper に似ています。変換を行わないメンバーは forMember を省略することができます。今回は mapFrom を使っていますが、ignore (変換を行わない) や fromValue (固定値を設定する) などの方法が提供されています。詳しくは forMember のドキュメントをご確認ください。

createMap<UserDTO, User>(
  mapper,
  'UserDTO',
  'User',
  forMember(_ => _.createdAt, mapFrom(_ => new Date(_.createdAt))),
  forMember(_ => _.updatedAt, mapFrom(_ => new Date(_.updatedAt)))
);

オブジェクトの変換

最初に定義した JSON を変換してみます。

const model = mapper.map<UserDTO, User>(json, 'UserDTO', 'User');

ちゃんと日付型になっていることを確認します。

console.log(model.createdAt.toUTCString());

以下のような出力が得られるはずです。

Sat, 01 Jan 2000 00:00:00 GMT

おわりに

今回はエンティティ モデルからビジネス モデルの変換を例に取りましたが、ビジネス モデルとビュー モデルでも同様の問題は発生しますし、バグを生み出しやすいところでもありますので、こうしたライブラリを使っていい感じに手抜きしていきたいですね。

Discussion