TypeScriptのユーティリティ型(Utility Types)は全部で22個ある

ユーティリティ型(Utility Types)とは

ユーティリティ型(Utility Types)とは一般的な型変換を容易にするための型です。

例えば、TypeScriptで任意のプロパティをピックアップしたオブジェクト型を作成したい場合は以下のようなコードになります。

TypeScript
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P]
}

type Person = {
  name: string
  age: number
  address: string
}

type PersonNameAndAge = MyPick<Person, 'name' | 'age'>

const person: PersonNameAndAge = {
  name: 'John',
  age: 30
}

console.log(person)

TypeScriptでは、このようなよく使用される型はユーティリティ型として用意されているため、前述のコードの場合は型を自作しなくてもPick<T, Keys>で実装できます。

TypeScript
type Person = {
  name: string
  age: number
  address: string
}

type PersonNameAndAge = Pick<Person, 'name' | 'age'>

const person: PersonNameAndAge = {
  name: 'John',
  age: 30
}

console.log(person)

ユーティリティ型は全部で22個

現在のユーティリティ型は全部で22個あります。(2024年7月現在)

TypeScriptの参考書やサバイバルTypeScriptなどのWebサイトだと、9個くらいしか書かれていないので、初心者だとユーティリティ型は全部で9個くらいだと思っている方もいます。

ユーティリティ型をすべて知らないと、TypeScriptの型定義を有効に活用できません。

この記事ではTypeScriptのユーティリティ型の全22個の使い方についてコード付きで解説します。

※ 記事内のユーティリティ型の見出しはアルファベット順で記載

1. Awaited<Type>

非同期関数のawaitやPromisesの.then()メソッドのような操作、特にPromisesを再帰的にアンラップする方法をモデル化します。

TypeScript
type Product = {
  id: number
  title: string
  // 以下略
}

type ProductType = Awaited<ReturnType<typeof getProduct>>

async function getProduct(id: number): Promise<Product> {
  const response = await fetch(`https://dummyjson.com/products/${id}`)
  // 中略
}

(async () => {
  const product: ProductType = await getProduct(1)
  document.getElementById('result')!.textContent = product.title
})()

※ ちなみにPromise<Type>はユーティリティ型ではない。

詳細は別記事をご参照ください。

2. Capitalize<StringType>

型の文字列の最初の文字を大文字に変換します。

TypeScript
type Greeting = 'hello world!'
type CapitalizeGreeting = Capitalize<Greeting>

const hello: CapitalizeGreeting = 'Hello world!'
console.log(hello)

3. ConstructorParameters<Type>

クラスのコンストラクタ引数の型を取得します。

TypeScript
class Person {
  constructor(public name: string, public age: number) {}
}

type PersonConstructorParameters = ConstructorParameters<typeof Person>
// type PersonConstructorParameters = [name: string, age: number]

const person: PersonConstructorParameters = ['John', 34]
console.log(person)

4. Exclude<UnionType, ExcludedMembers>

任意の型を除外します。

TypeScript
type Fruit = 'apple' | 'orange' | 'grape' | 'mikan'
type Citrus = Exclude<Fruit, 'apple' | 'grape'>
// type Citrus = "orange" | "mikan"

5. Extract<Type, Union>

任意の型を抽出します。

TypeScript
type Fruit = 'apple' | 'orange' | 'grape' | 'mikan'
type NotCitrus = Extract<Fruit, 'apple' | 'grape'>
// type NotCitrus = "apple" | "grape"

6. InstanceType<Type>

与えられたclass型からそのインスタンスの型を取得します。

オブジェクトの型に使う場合は有用だが、new Personで変数に入れる場合は型推論が効くので、あまり意味がない。

TypeScript
class Person {
  constructor(public name: string, public age: number) {}

  greet() {
    console.log(`My name is ${this.name}`)
  }
}

type PersonInstance = InstanceType<typeof Person>

const person: PersonInstance = {
  name: 'John',
  age: 34,
  greet() {
    console.log(`Hello, ${this.name}!`)
  },
}

person.greet()

7. Lowercase<StringType>

型の文字列の各文字を小文字に変換します。

TypeScript
type Greeting = 'HELLO WORLD!'
type CapitalGreeting = Lowercase<Greeting>

const hello: CapitalGreeting = 'hello world!'
console.log(hello)

8. NoInfer<Type>

型推論を防止します。

TypeScript
function findIndexInArray<T extends string>(
  elements: T[],
  item: NoInfer<T>
): string {
  return elements.find((el) => el === item)
}

type FoodType = 'apple' | 'banana' | 'cookie';
const foods: FoodType[] = ['apple', 'banana', 'cookie']

findIndexInArray(foods, 'apple')
findIndexInArray(foods, 'grape')
// Argument of type '"grape"' is not assignable to parameter of type 'FoodType'.

9. NonNullable<Type>

nullとundefinedを除外して型を返します。

TypeScript
type MyType = string | number | null | undefined
type NonNullMyType = NonNullable<MyType>
// string | number

10. Omit<Type, Keys>

型から指定したプロパティを除外します。

TypeScript
type Person = {
  name: string
  age: number
  address: string
}

type PersonWithoutAge = Omit<Person, 'age'>
// type PersonWithoutAge = {
//   name: string;
//   address: string;
// }

11. OmitThisParameter<Type>

関数型からthis引数を取り除いた新しい関数型を作成します。

TypeScript
type Example = {
  method(this: { name: string }, arg: string): void
}

type ExampleWithoutThis = OmitThisParameter<Example['method']>
// type ExampleWithoutThis = (arg: string) => void

12. Parameters<Type>

関数型からその引数の型を抽出してタプル型として取得します。

TypeScript
function add(a: number, b: number): string {
  return `Answer is ${a + b}!`
}

type AddParam = Parameters<typeof add>
// type AddParam = [a: number, b: number]

13. Partial<Type>

元の型のすべてのプロパティをオプショナルにした新しい型を作成します。

TypeScript
type Person = {
  name: string;
  age: number;
  address: string;
}

type PartialPerson = Partial<Person>
// type PartialPerson = {
//   name?: string;
//   age?: number;
//   address?: string;
// }

14. Pick<Type, Keys>

元の型から指定したキーを取り出して、新しい型を作成します。

TypeScript
type Person = {
  name: string
  age: number
  address: string
}

type NameAndAge = Pick<Person, 'name' | 'age'>
// type NameAndAge = {
//   name: string;
//   age: number;
// }

15. Readonly<Type>

元の型のすべてのプロパティを読み取り専用にした新しい型を作成します。

TypeScript
type Person = {
  name: string
  age: number
  address: string
}

type ReadonlyPerson = Readonly<Person>
// type ReadonlyPerson = {
//   readonly name: string;
//   readonly age: number;
//   readonly address: string;
// }

16. Record<Keys, Type>

指定されたキーに対して、指定された型の値を持つオブジェクトを作成します。

TypeScript
type ExampleRecord = Record<'foo' | 'bar' | 'baz', string>
// type ExampleRecord = {
//   foo: string;
//   bar: string;
//   baz: string;
// }

以下のように組み合わせることもできます。

TypeScript
type Role = 'admin' | 'user'
type RolePermissions = {
  canEdit: boolean
  canView: boolean
}
type RoleRecord = Record<Role, RolePermissions>

const rolePermissions: RoleRecord = {
  admin: {
    canEdit: true,
    canView: true,
  },
  user: {
    canEdit: false,
    canView: true,
  }
}
console.log(rolePermissions)

17. Required<Type>

元の型のすべてのプロパティを必須にした新しい型を作成します。

TypeScript
type Person = {
  name: string
  age?: number
  address?: string
}

type RequiredPerson = Required<Person>
// type RequiredPerson = {
//   name: string;
//   age: number;
//   address: string;
// }

18. ReturnType<Type>

関数型の引数として渡された場合に、その関数の返り値の型を取得します。

TypeScript
function getUser() {
  return {
    id: 1,
    name: 'John',
  }
}

type User = ReturnType<typeof getUser>
// type User = {
//   id: number;
//   name: string;
// }

19. ThisParameterType<Type>

関数型の型引数として指定された関数のthisパラメーターの型を取得します。

TypeScript
const user = {
  name: 'John',
  greet(this: { name: string }) {
    console.log(`Hello, ${this.name}`)
  },
}

type ThisType = ThisParameterType<typeof user.greet>
// type ThisType = {
//   name: string;
// }

20. ThisType<Type>

クラスやオブジェクトのメソッドのthis型を指定します。

TypeScript
const user = {
  name: 'John',
  greet(this: { name: string }) {
    console.log(`Hello, ${this.name}`)
  },
}

type This = ThisType<typeof user.greet>
// type This = ThisType<(this: {
//   name: string;
// }) => void>
TypeScript
const user = {
  name: 'John',
  greet(this: { name: string }) {
    console.log(`Hello, ${this.name}`)
  },
}

type This = ThisType<typeof user.greet>
// type This = ThisType<(this: {
//   name: string;
// }) => void>

21. Uncapitalize<StringType>

型の文字列の最初の文字を小文字に変換します。

TypeScript
type Greeting = 'Hello World!'
type UncapitalizeGreeting = Uncapitalize<Greeting>

const hello: UncapitalizeGreeting = 'hello World!'
console.log(hello)

22. Uppercase<StringType>

型の文字列の各文字を大文字に変換します。

TypeScript
type Greeting = 'hello world!'
type UppercaseGreeting = Uppercase<Greeting>

const hello: UppercaseGreeting = 'HELLO WORLD!'
console.log(hello)