きっちり理解する！TypeScriptのUtility Typesの使い方と活用法

## はじめに
TypeScriptにはUtility Typesという、よく使うであろう型変換を簡単にするための型が用意されています。

あまり業務で使ったことはないのですが、使いこなせれば便利だなと思ったので、そのいくつかを紹介します。
まったくUtility Typesに明るくないので、AIのClaudeに聞いて使用頻度が高い（らしい）ものをピックアップしました。

## Partial\<T\>
### 概要
ジェネリクスに指定したオブジェクト型のプロパティをすべてオプショナルに変えることができます。

### 使用例
```typescript
interface UserProfile {
  name: string;
  email: string;
  age: number;
  address: string;
}

const updateUserProfile = (userId: string, updates: Partial<UserProfile>) => {
  // データベースの更新処理（擬似コード）
  console.log(`userId:${userId} updates:${JSON.stringify(updates)}`);
};

// すべて指定
updateUserProfile("001", {
  name: "John",
  email: "test@mail",
  age: 28,
  address: "Japan",
});

// 一部のみ指定
updateUserProfile("002", {
  name: "Kevin",
  age: 21,
});
```
ユーザーIDを元に、プロフィールを更新する処理を考えます。
更新対象のデータは可変にしたいので、オプショナルにしたいです。
ただし、`UserProfile`型はほかでも使いたいので、この型をオプショナルにすることはできません。

そこで、Partialを使用して、プロパティがすべてオプショナルとなった新しい`UserProfile`を更新対象の型として設定しました。

実行結果は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/b59f9b8b-4c77-d6aa-1365-3a40ba291444.png)

更新対象は任意項目なので、全部または一部のみの指定も可能になっています。

## Required\<T\>
### 概要
ジェネリクスに指定したオブジェクトの型のプロパティをすべて必須に変えることができます。
Partialの逆の挙動になります。

### 使用例
```typescript
interface DatabaseConfig {
  host?: string;
  port?: number;
  username?: string;
  password?: string;
}

// デフォルト設定
const defaultConfig: DatabaseConfig = {
  host: "localhost",
  port: 5432,
};

function createConnection(dynamicConfig: DatabaseConfig): void {
  const fullConfig: Required<DatabaseConfig> = {
    host: dynamicConfig.host ?? defaultConfig.host!,
    port: dynamicConfig.port ?? defaultConfig.port!,
    username: dynamicConfig.username ?? promptUsername(),
    password: dynamicConfig.password ?? promptPassword(),
  };
  // 接続処理の模擬
  console.log(fullConfig);
}

// プロンプトを模擬するヘルパー関数
const promptUsername = () => "username"; // 実際はユーザーからの入力を受け付ける
const promptPassword = () => "password"; // 実際はユーザーからの入力を受け付ける

// 使用例
// すべて指定
createConnection({
  host: "192.168.1.1",
  port: 8081,
  username: "db_user",
  password: "db_pass",
});
// hostとportはデフォルト値、usernameとpasswardは入力値で設定
createConnection({});
```
DB接続の処理について考えます。
DB接続時、設定情報は欠けていてほしくないので、すべて必須のプロパティとしたいです。
しかし、デフォルト値を使用したり、動的に設定できるようにしたり、と柔軟に設定できるようにもしたいです。

この場合、もともとの`DatabaseConfig`のすべてを必須プロパティとすると、柔軟さが失われます。

そのため、型定義自体はすべてオプショナルとしておき、最終的なDBの設定値を受け渡すときには必須項目となるようにRequiredを使用しています。

これにより、設定は柔軟にしつつ、設定情報がかけることのない実装にすることができます。


## Pick\<T, K\>
### 概要
オブジェクトから特定のプロパティだけを選択して新しい型を作成します。
大きなオブジェクトから必要な部分だけを抽出する際に便利です。

### 使用例
```typescript
interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  category: string;
  inStock: boolean;
}

type ProductSummary = Pick<Product, "id" | "name" | "price">;

// スタブデータ
const products: Product[] = [
  {
    id: "1",
    name: "Laptop",
    price: 999.99,
    description: "Powerful laptop",
    category: "Electronics",
    inStock: true,
  },
  {
    id: "2",
    name: "Smartphone",
    price: 499.99,
    description: "Latest model",
    category: "Electronics",
    inStock: true,
  },
  {
    id: "3",
    name: "Headphones",
    price: 99.99,
    description: "Noise-cancelling",
    category: "Audio",
    inStock: false,
  },
];

const getProductList = (): ProductSummary[] => {
  return products.map(({ id, name, price }) => ({ id, name, price }));
};

console.log(getProductList());
```
DBのデータから特定のデータを取得する場合を考えます。
すべてのデータを持ち回るのは扱いにくいので、特定のデータのみ抽出して扱えるようにしたいです。

そんなとき、Pick\<T,K\>が使えます。

ジェネリクスの１つめ（T）にはベースとなる型、２つ目（K）には抽出対象としたいプロパティをリテラル型で指定します。

このようにすることで`Product`をベースとした、`ProductSummary`という限定した型を作成することができます。

## Omit\<T, K\>
### 概要
Pickの逆で、特定のプロパティを除外して新しい型を作成します。
不要なプロパティを除外したい場合に使用します。

### 使用例
```typescript
interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  category: string;
  inStock: boolean;
}

type ProductDetails = Omit<Product, "id" | "inStock">;

const updateProduct = (id: string, details: ProductDetails): void => {
  console.log(`Updating product with id ${id}:`, details);
  // 実際のデータベース更新処理はここで行われる
};

const productId = "abc123";
const updatedDetails: ProductDetails = {
  name: "Updated Product",
  price: 1999,
  description: "This is an updated product",
  category: "Electronics",
};

updateProduct(productId, updatedDetails);
```
DB更新の処理を考えます。

テーブルのカラム情報と一致した型を用意しています。
更新データを作成するときもこの型を使いたいのですが、PKである`id`と在庫状況を表す`inStock`は更新したくないとします。

そんなとき、Omit\<T, K\>が使えます。

ジェネリクスの１つめ（T）にはベースとなる型、２つ目（K）には除外したいプロパティをリテラル型で指定します。

このようにすることで、`Product`をベースとした、`ProductDetails`という更新処理データのための型を生成することができます。

## まとめ
今回は4つのUtility Typesを紹介しました。
どれも覚えておけば活躍する場は結構ありそうです。

Utility Typesは20近くあり、まだまだ紹介したいものがたくさんあるので、また別の機会に紹介する記事を書ければと思います。