【TypeScript】Utility Types で型を再利用

# はじめに
この記事では、TypeScript の主要な Utility Types について記載します。Utility Types では、型から別の型を導き出すこと（型変換）ができます。

https://www.typescriptlang.org/docs/handbook/utility-types.html

# 開発環境
開発環境は以下の通りです。

- Windows11
- VSCode
- TypeScript 5.5.3

# [`Partial<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype)
全てのプロパティをオプションにします。

- `T` :  オブジェクト型

```index.ts
type ToDo = {
  title: string;
  description: string;
};

type PartialToDo = Partial<ToDo>;

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/142bac46-91de-c89a-7861-ce78b0ffc6f8.png)

# [`Required<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype)
全てのプロパティを必須にします。`Partial<T>` の逆。

- `T` :  オブジェクト型

```index.ts
type ToDo = {
  title: string;
  description?: string;
};

type RequiredToDo = Required<ToDo>;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/1a948c40-7c79-8530-9932-f3569eff82ee.png)

# [`Readonly<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype)
全てのプロパティを読み取り専用にします。

- `T` :  オブジェクト型

```index.ts
type ToDo = {
  title: string;
  description: string;
};

type ReadonlyToDo = Readonly<ToDo>;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/ba1d350d-d0be-d36e-3144-828bf3858445.png)

:::note
読み取り専用 = 代入不可 になります。

- 代入可

```index.ts
const toDo: ToDo = {
  title: "cleaning",
  description: "clean my room",
};

toDo.description = "clean bathroom";
```

- 代入不可

```index.ts
const toDo: ReadonlyToDo = {
  title: "cleaning",
  description: "clean my room",
};

// Cannot assign to 'description' because it is a read-only property.ts(2540)
toDo.description = "clean bathroom";
```
:::

:::note
`readonly` は指定したそのプロパティだけが読み取り専用になります。

```index.ts
type Obj = {
  readonly toDo: ToDo;
};

const Object: Obj = {
  toDo: {
    title: "cleaning",
    description: "clean my room",
  },
};

// 代入不可
// Cannot assign to 'description' because it is a read-only property.ts(2540)
Object.toDo = {
  title: "shopping",
  description: "buy tomato",
};

// 代入可
Object.toDo.description = "clean bathroom";
```
:::

# [`Record<Kyes, Type>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)
プロパティのキーが `Keys`・バリュー（値）が `Type` であるオブジェクト型を作ります。

- `Kyes`
    - オブジェクトのプロパティキーを指定
    - `string`、`number`、`symbol` とそれぞれのリテラル型が代入可
- `Type`
    - オブジェクトのバリュー（値）の型を指定
    - 任意の型が代入可

```index.ts
type ToDo = Record<"title" | "description", string>;

const toDo: ToDo = {
  title: "cleaning",
  description: "clean my room",
};
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/1c74f51c-8d65-1fd8-160e-9ad2baeda09a.png)

:::note
`Kyes` を `string` のリテラル型にした例

```index.ts
type Member = "Wyatt" | "Billy";

type ToDo = {
  title: string;
  description: string;
};

type RecordToDo = Record<Member, ToDoB>;

const toDos: RecordToDo = {
  Wyatt: {
    title: "cleaning",
    description: "clean my room",
  },
  Billy: {
    title: "shopping",
    description: "buy tomato",
  },
};
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/8442c2b4-39c0-ea57-ab16-79214c8b2125.png)

:::

# [`Pick<T, Keys>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys)
オブジェクト型 `T` から `Keys` に指定したキーだけを含むオブジェクト型を作ります。

- `T` : オブジェクト型
- `Keys` : `T` のプロパティキー

```index.ts
type ToDo = {
  id: number;
  title: string;
  description: string;
  deadline: Date;
};

type PickToDo = Pick<ToDo, "title" | "description">;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/70b1f0c1-0cf5-85de-56b2-9919933a69d1.png)

# [`Omit<T, Keys>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)
オブジェクト型 `T` から `Keys` に指定したキーを除いたオブジェクト型を作ります。`Pick<T, Keys>` の逆。

- `T` : オブジェクト型
- `Keys` : `T` のプロパティキー

```index.ts
type ToDo = {
  id: number;
  title: string;
  description: string;
  deadline: Date;
};

type OmitToDo = Omit<ToDo, "title" | "description">;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/b7d236a1-a131-c972-a868-6b1f10da8031.png)

# [`Exclude<T, U>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers)
ユニオン型 `T` から `U` に指定した型を取り除いたユニオン型を作ります。`Omit<T, Keys>` はオブジェクト型で、`Exclude<T, U>` はユニオン型。

- `T` : ユニオン型
- `U` : `T` から取り除きたい型

```index.ts
type ToDo = "cleaning" | "shopping" | "washing" | "cooking";

type ExcludeToDo = Exclude<ToDo, "washing" | "cooking">;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/48183a52-7e5c-f18d-bbd4-f97d6f686393.png)

:::note
ユニオン型の各型がオブジェクト型でも利用できます。

```index.ts
type ToDo =
  | { title: "cleaning"; description: "clean my room" }
  | { title: "shopping"; description: "buy tomato" }
  | { title: "washing"; description: "wash t-shirt" }
  | { title: "cooking"; description: "cook dinner" };

type ExcludeToDo = Exclude<
  ToDo,
  | { title: "washing"; description: "wash t-shirt" }
  | { title: "cooking"; description: "cook dinner" }
>;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/4fa5dfb2-11e2-3337-289b-65da5f2c9800.png)

:::

:::note warn
`U` は `T` の部分集合ではないので、`T` 変更時、用途によっては `U` も変更する必要があります。
例えば、`"cooking"` を `"packing"` に変更し、`"packing"` を `ExcludeToDo` に含めたくない場合、`ExcludeToDo` も変更する必要があります。

```index.ts
type ToDo = "cleaning" | "shopping" | "washing" | "packing";

export type ExcludeToDo = Exclude<ToDo, "washing" | "cooking">;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/de35c6f9-4c6a-22f5-53d1-34b4dd2e8e8c.png)

:::

# [`Extract<T, U>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union)
ユニオン型 `T` から `U` に指定した型を抽出したユニオン型を作ります。`Exclude<T, U>` の逆。`Pick<T, Keys>` はオブジェクト型で、`Extract<T, U>` はユニオン型。

- `T` : ユニオン型
- `U` : `T` から抽出したい型

```index.ts
type ToDo = "cleaning" | "shopping" | "washing" | "cooking";

type ExtractToDo = Extract<ToDo, "washing" | "cooking">;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/5dea1c25-cef9-641d-01a3-43ebad388927.png)

# 参考
- [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
- [ユーティリティ型 (utility type)](https://typescriptbook.jp/reference/type-reuse/utility-types)