TypeScriptの型をよりスマートに使いこなすために

TypeScriptにおいて、「型」は非常に重要な概念です。今回は、型をよりスマートに効率的に書くための **Mapped Types** と **ユーティリティ型** について扱おうと思います。


## **1. Mapped Typesとは？**

**Mapped Types** とは、**既存の型を基にして、新しい型を作成する仕組み** です。これは、オブジェクトのプロパティを動的に変換する際に便利です。

例えば、すべてのプロパティを `readonly` にしたい場合、通常はこのように記述すると思います。

```typescript
type User = {
  id: number;
  name: string;
  email: string;
}

type ReadonlyUser = {
  readonly id: number;
  readonly name: string;
  readonly email: string;
}
```

Userのプロパティが今は3つですが、これが10, 20個と増えた際にすべてにreadonlyをつけるのは少し冗長で見映えが悪いです。
**Mapped Types** を使った場合、以下のようにより簡潔に記述できます。

```typescript
type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
}
```

これで先ほどと同様、 `User` 型のすべてのプロパティが `readonly` になりました。

<br />

## **2. 基本のMapped Types**

### **1. すべてのプロパティをオプショナルにする (**`Partial<T>`**)**

```typescript
type PartialUser = {
  [K in keyof User]?: User[K]
}
```

**ユースケース**

-   一部のデータのみ更新したい時
-   フォームの入力値を部分的に扱いたい時
    

### **2. すべてのプロパティを必須にする (**`Required<T>`**)**

```typescript
type RequiredUser = {
  [K in keyof User]-?: User[K]
}
```

**ユースケース**

-   APIのレスポンスで全データが必ず存在する場合
    

### **3. すべてのプロパティを** `readonly` **にする (**`Readonly<T>`**)**

```typescript
type ReadonlyUser = {
  readonly [K in keyof User]: User[K]
}
```

 **ユースケース**

-   オブジェクトの変更を防ぎたい時（Reactの`props` など）
    
<br />

## **3. TypeScriptのユーティリティ型を活用しよう！**

TypeScriptには、開発を効率化する **便利なユーティリティ型** が色々用意されています。

### **1.  `Pick<T, K>` : 指定したプロパティだけを抽出**

```typescript
// Userからidとnameプロパティだけを抽出
type PickUser = Pick<User, "id" | "name">
```

**ユースケース**

-   APIレスポンスで必要なプロパティだけを取得
    

### **2. `Omit<T, K>` : 指定したプロパティを除外**

```typescript
// Userのうちemail以外のプロパティを抽出
type OmitUser = Omit<User, "email">
```

**ユースケース**

-   ユーザー情報から個人情報を取り除いたデータを作成
    

### **3. `Record<K, T>`** : ユニオン型から特定のキーと型を持つオブジェクトを作成**

```typescript
type Role = "admin" | "user" | "guest"
type RolePermissions = Record<Role, boolean>

// ↑はこれと同じ
type RolePermissions = { 
	admin: boolean; 
	user: boolean; 
	guest: boolean; 
}
```

**ユースケース**

-   ユーザーの権限管理（admin, user, guestのみに限定したい）
    

### **4. `Extract<T, U>` : ユニオン型から指定した型にマッチするものだけを抽出**

```typescript
// Statusからactive, bannedだけを抽出
type Status = "active" | "inactive" | "banned"
type ActiveStatus = Extract<Status, "active" | "banned">
```

**ユースケース**

-   特定の条件に合致する型だけを扱う
    

### **5. `Exclude<T, U>` : ユニオン型から指定した型を除外**

```typescript
// Statusからactive以外を抽出
type NonActiveStatus = Exclude<Status, "active">
```

**ユースケース**

-   必要のない型を削除
    
<br />

## **4. 応用編：高度なMapped Typesとユーティリティ型の組み合わせ**

### **1. プロパティの型を変換する**

例えば、すべてのプロパティを `string` に変換する場合

```typescript
type Stringify<T> = {
  [K in keyof T]: string
}

type StringifiedUser = Stringify<User>
```

**ユースケース**

-   数値や日付データをすべて文字列として扱うケース
    

### **2. プロパティを一部変更する (**`Override<T, U>` **の応用)**

特定のプロパティだけ変更したい場合

```typescript
type Override<T, U> = {
  [K in keyof T]: K extends keyof U ? U[K] : T[K]
}

// `name` だけ型が `number` に
type UserWithNewName = Override<User, { name: number }>
```

**ユースケース**

-   一部のプロパティの型を変更して新しい型を作る
    
<br />

## **5. 最後に**

今回取り上げたTypeScriptの`Mapped Types`と`ユーティリティ型`を使うと、**柔軟で再利用性の高い型定義** を作ることができ、開発体験が向上します。

＊ **基本のMapped Types**：`Partial<T>`, `Required<T>`, `Readonly<T>` 
＊ **便利なユーティリティ型**：`Pick<T, K>`, `Omit<T, K>`, `Record<K, T>`, `Extract<T, U>`, `Exclude<T, U>` 
＊ **応用編**：型の変換 (`Stringify<T>`)、一部変更 (`Override<T, U>`) など

これらを使いこなしてよいTypeScriptライフを！

<br />

## **参考サイト**

https://www.typescriptlang.org/docs/

<br />

## **採用拡大中！**

アシストエンジニアリングでは一緒に働くフロントエンド、バックエンドのエンジニア仲間を募集しています！
少しでも興味ある方は、カジュアル面談からでもぜひお気軽にお話ししましょう！

お問い合わせはこちらから↓  
[https://official.assisteng.co.jp/contact/](https://official.assisteng.co.jp/contact/)