🔄

AutoMapper TypeScript を使ってみる

に公開

はじめに

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,
}

ビジネスエンティティとして扱うためのインターフェイスを定義します。createdAt と updatedAt は日付型です。

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