【TypeScript】factory.tsのすすめ

## はじめに

- オブジェクト生成処理がソースコードの色々な箇所に乱立して困ったことがあります。それを解決できるライブラリがあるので紹介します。

## factory.tsについて

https://www.npmjs.com/package/factory.ts

- Factoryメソッドが簡単に作成出来るライブラリです。
- オブジェクト生成時にIDなどを連番してくれる機能なども標準搭載しています。
- オブジェクト生成時に指定プロパティの上書きも可能です。
- ネストしたオブジェクトの生成にも対応可能です。

## 対象読者

- 同じようなオブジェクト初期化処理が複数のソースコードに乱立して苦労している人
- テストコードのオブジェクト初期化処理が乱立して苦労している人

## 動作環境

- Node.js - 14.x
- TypeScript - 4.5.x
- factory.ts - 0.5.x

## サンプルコード

### 標準パターン

```src/sample1.ts
import * as Factory from 'factory.ts';

type SampleData = {
  firstName: string;
  lastName: string;
};

const sampleDataFactory = Factory.Sync.makeFactory<SampleData>({
  firstName: 'Bob',
  lastName: 'Kojima',
});

const obj = sampleDataFactory.build();
console.log(`obj - name:${obj.lastName} ${obj.firstName}`);
```

**実行結果**

```bash
obj - name:Kojima Bob
```

### プロパティの上書き

```src/sample2.ts
import * as Factory from 'factory.ts';

type SampleData = {
  firstName: string;
  lastName: string;
};

const sampleDataFactory = Factory.Sync.makeFactory<SampleData>({
  firstName: 'Bob',
  lastName: 'Kojima',
});

const obj = sampleDataFactory.build({ lastName: 'Goto' });
console.log(`obj - name:${obj.lastName} ${obj.firstName}`);
```

**実行結果**

```bash
obj - name:Goto Bob
```

### ID連番確認

```src/sample3.ts
import * as Factory from 'factory.ts';

type SampleData = {
  id: number;
};

const sampleDataFactory = Factory.Sync.makeFactory<SampleData>({
  id: Factory.each((i) => i),
});

const obj1 = sampleDataFactory.build();
const obj2 = sampleDataFactory.build();
console.log(`obj1 - id:${obj1.id}`);
console.log(`obj2 - id:${obj2.id}`);
```

**実行結果**

```bash
obj1 - id:0
obj2 - id:1
```

### 複数件同時生成

```src/sample4.ts
import * as Factory from 'factory.ts';

type SampleData = {
  id: number;
  name: string;
};

const sampleDataFactory = Factory.Sync.makeFactory<SampleData>({
  id: Factory.each((i) => i),
  name: 'Kawamoto',
});

const items = sampleDataFactory.buildList(2);
console.log(`items[0] - id:${items[0].id}, name:${items[0].name}`);
console.log(`items[1] - id:${items[1].id}, name:${items[1].name}`);
```

**実行結果**

```bash
items[0] - id:0, name:Kawamoto
items[1] - id:1, name:Kawamoto
```

### プロパティ追加

```src/sample5.ts
import * as Factory from 'factory.ts';

type SampleData = {
  id: number;
};

const sampleDataFactory = Factory.Sync.makeFactory<SampleData>({
  id: Factory.each((i) => i),
});
const nameFactory = Factory.Sync.makeFactory({
  name: 'Kojima',
});

const idAndNameFactory = sampleDataFactory.combine(nameFactory);

const obj = idAndNameFactory.build();
console.log(`obj - id:${obj.id}, name:${obj.name}`);
```

**実行結果**

```bash
obj - id:0, name:Kojima
```

### Factoryをネスト

```src/sample6.ts
import * as Factory from 'factory.ts';

type SampleData1 = {
  name: string;
};

type SampleData2 = {
  data: SampleData1;
  items: SampleData1[];
};

const sampleData1Factory = Factory.Sync.makeFactory<SampleData1>({
  name: 'Nagane',
});

const sampleData2Factory = Factory.Sync.makeFactory<SampleData2>({
  data: sampleData1Factory.build(),
  items: sampleData1Factory.buildList(2),
});

const obj = sampleData2Factory.build();
console.log(`obj.data - name:${obj.data.name}`);
console.log(`obj.items[0] - name:${obj.items[0].name}`);
console.log(`obj.items[1] - name:${obj.items[1].name}`);
```

**実行結果**

```bash
obj.data - name:Nagane
obj.items[0] - name:Nagane
obj.items[1] - name:Nagane
```

### サンプルコード一式

https://github.com/yasu-s/factory.ts-sample/tree/demo

## おわりに

- オブジェクト生成処理がコンパクトになり共通化出来るので再利用性が増します。
- 重複コードを減らすことが出来ます。
- オブジェクト生成処理が乱立しているソースコードに対してリファクタリングの一環として導入するのはいかがでしょうか。