🐕

絶対に知るべきTypescriptのユーティリティ型

2023/04/14に公開

はじめに

この記事は以下の記事の和訳になります。なお、著者には許可をいただいております。
是非原文もご覧ください。

https://dev.to/arafat4693/typescript-utility-types-that-you-must-know-4m6k


こんにちは、みなさん、今回この記事では、あなたの生活を楽にしてくれるいくつかの便利で重要なTypescriptのユーティリティ型について見ていこうと思います。

Typescriptのユーティリティ型は、他の新しい型を作成もしくは操作するために使うことができる、事前に定義されたジェネリック型になります。これらの型は全てのTypescriptのプロジェクトでグローバルに使うことができるので、依存関係を追加したりすることなく使うことができます。

目次

Partial

まずはじめに見ていくユーティリティ型は、Partialで、その名の通り、全てを任意もしくは部分的にします。

こちらがユーティリティ型Partialの例です:

interface Person {
  name: string;
  age: number;
  email: string;
}

// 'PartialPerson'という、Personの部分的なバージョンの型である、新しい型を定義します。
type PartialPerson = Partial<Person>;

// 以下と同じ:
// interface Person {
//   name?: string | undefined;
//   age?: number | undefined;
//   email?: string | undefined;
// }

Required

Partialとは反対のユーティリティ型で、全てを必須にします。

interface Person {
 name?: string | undefined;
 age?: number | undefined;
 email?: string | undefined;
}

// 'RequiredPerson'という、'Person'の必須バージョンの新しい型を定義します。
type RequiredPerson = Required<Person>;

// 以下と同じ:
// interface Person {
//   name: string;
//   age: number;
//   email: string;
// }

Omit

Omitユーティリティ型を使えば、規定の型から新しい型を作ることができます、がその型はいくつかのプロパティが削除されます。

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type UserWithoutEmail = Omit<User, 'email'>;

// 以下と同じ: 
// interface Person {
//   id: string;
//   name: string;
//   age: number;
// }

unionを渡すことによって、複数のプロパティを削除することもできます。

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type UserWithoutEmailAndName = Omit<User, 'email' | 'name'>;

// 以下と同じ: 
// interface Person {
//   id: string;
//   age: number;
// }

Pick

Omitと反対のユーティリティ型として、Pickを使えば、規定の型からあるプロパティのセットだけを含む新しい型を作成することができます。

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type UserWithEmailAndName = Pick<User, 'email' | 'name'>;

// 以下と同じ: 
// interface Person {
//   name: string;
//   email: string;
// }

複数のユーティリティ型を同時に使用する

複数のユーティリティ型を同時に使うこともできます。例えば:

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type PartialPick = Partial<Pick<User, 'email' | 'name'>>;

// 以下と同じ: 
// interface Person {
//   name?: string | undefined;
//   email?: string | undefined;
// }

他の例:

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type OmitPartialPick = Omit<Partial<Pick<User, 'email' | 'name'>>, 'email'>;

// 以下と同じ: 
// interface Person {
//   name?: string | undefined;
// }

Readonly

Readonlyユーティリティ型を使えば、規定の型のセットをreadonlyとして作成することができ、初期化の後は全てのプロパティが変更不可能になります。

interface Person {
  id: number;
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;

// 以下と同じ:
// interface Person {
//   readonly id: number;
//   readonly name: string;
//   readonly age: number;
// }

const person: ReadonlyPerson = {
  id: 1,
  name: 'John',
  age: 25
};

person.name = 'Mike'; // Error: Cannot assign to 'name' because it is a read-only property.

Mutable

Mutableという型ヘルパーを作成し、読み込み専用の型を変更可能な型に変換することもできます。

interface Person {
  readonly id: number;
  readonly name: string;
  readonly age: number;
}

// Mutableのシンタックスは以下の通り:
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

type MutablePerson = Mutable<Person>;

// 以下と同じ:
// interface Person {
//   id: number;
//   name: string;
//   age: number;
// }

Exclude

Excludeユーティリティ型を使えば、unionのメンバを削除した新しい型を作成することができます。

type NumberOrString = number | string;
type OnlyNumber = Exclude<NumberOrString, string>;

// 以下と同じ:
// type OnlyNumber = number;

const num: OnlyNumber = 5;
const str: OnlyNumber = 'hello'; // Error: Type '"hello"' is not assignable to type 'number'.

ユニオンの複数のメンバを削除することもできます。

type NumberStringOrBoolean = number | string | boolean;
type OnlyBoolean = Exclude<NumberStringOrBoolean, string | number>;

// same as:
// type OnlyBoolean = boolean;

Extract

Excludeの反対のユーティリティ型として、Extract型を使えば、ユニオン型から一つもしくは複数の項目を抽出することができます:

type NumberOrString = number | string | boolean;
type OnlyNumber = Extract<NumberOrString, number>;

// 以下と同じ:
// type OnlyNumber = number;

ReturnType

ReturnTypeユーティリティ型を使えば、関数の戻り値の型を抽出することができます。関数の型を引数として渡し、その関数の戻り値の型を返します。

function add(a: number, b: number): number {
  return a + b;
}

type AddReturnType = ReturnType<typeof add>;
// type AddReturnType = number;

// ---

function addStr(a: string, b: string): string{
  return a + b;
}

type AddReturnType2 = ReturnType<typeof addStr>;
// type AddReturnType2 = string;

Parameters

Parametersユーティリティ型を使えば、関数の引数の型を抽出することができるようになります。

function add(a: number, b: string, c:boolean): string {
  return a + b;
}

type AddReturnType = Parameters<typeof add>;
// type AddReturnType = [a: number, b: string, c:boolean];

NonNullable

NonNullableユーティリティ型を使えば、与えられた型から、nullundefinedを除去した新しい型を作成することができるようになります。

type NullableString = string | null | undefined;

type NonNullableString = NonNullable<NullableString>;
// type NonNullableString = string;

const str1: NullableString = null;
const str2: NonNullableString = 'hello';
const str3: NonNullableString = null; // Error: Type 'null' is not assignable to type 'string'.

Awaited

Awaitedユーティリティ型を使えば、promiseもしくはawaitを使う他の型の、resolveされた後の型を抽出することができます。

type promiseNumber = Promise<number>

type justNumber = Awaited<Promise<number>>
// type justNumber = number

AwaitedとReturnTypeの合わせ技

こちらはReturnTypeAwaitedを同時に使う例です:

async function fetchData(): Promise<string> {
  // fetch data from API and return a string
}

type ResolvedResult = Awaited<ReturnType<typeof fetchData>>;
// type ResolvedResult = string

この例では、stringのPromisePromise<string>)を返す、非同期関数を定義します。そして、ReturnTypeを使い、fetchDataの戻り値の型を抽出し、Awaitedの引数としてそれを渡し、promiseがresolveされた時の型を抽出しています。

おわりに

世界中の開発者達に非常によく使われているTypescriptのユーティリティ型のいくつかを紹介しました。これらはあなたのコードをクリーンにし、型をより表現豊かに、そして簡潔にすることができるでしょう。この記事があなたの役に立つことを願い、もし他に重要なユーティリティ型を見逃していた場合、コメントで教えてくれると助かります。記事を読んでいただきありがとうございます。次の記事でお会いしましょう🐼。

Discussion