Utility Typesとは
Utility Types
とはコード内で型変換を容易にする為にTypeScriptが提供する(便利な関数のような)型達です。
Partial<T>
Partial<T>
はT
の全てのプロパティをOptional(任意)のプロパティにしてくれます。
下記のコードPerson
では1つも任意のプロパティが設定されていませんが、Partial<T>
を使用する事で、変数taro
ではfirstName
のみを持つ事ができています。
interface Person {
firstName: string
lastName: string
age: number
}
const taro: Partial<Person> = {
firstName: 'Taro',
}
console.log(taro); //=> { firstName: 'Taro' }
Required<T>
Required<T>
はT
の全てのプロパティを必須のプロパティにしてくれます。
下記のコードPerson
では全てが任意のプロパティが設定されていますが、Required<T>
を使用する事で、変数jiro
ではfirstName
とlastName
の両方を与えてあげないと、エラーが発生します。
interface Person {
firstName?: string
lastName?: string
}
const jiro: Required<Person> = {
firstName: 'Taro',
}
// Error: property 'lastName' is missing.
Readonly<T>
Readonly<T>
はT
の全てのプロパティをreadonly
のプロパティにしてくれます。
下記ではReadonly<Todo>
としているため、Todo
のオブジェクトであるtodo
のtitle
を更新しようとするとエラーが発生します。
interface Todo {
title: string
}
const todo: Readonly<Todo> = {
title: '家の掃除',
}
todo.title = '夕飯の買い出し' // Cannot assign to 'title' because it is a read-only property.ts(2540)
Record<K, T>
Record<K, T>
はK
がプロパティとなりT
型を持つレコード型を構築します。
言葉ではややわかりずらいので、下記の例を元に考えています。
Record<K, T>
のK
にはnumber
が指定されています。そして、T
にはUser
が指定されています。
このことから、Record<K.T>
を使用して作成されたUserList
型はnumber
型がプロパティとなり、User
をもつ型となります。
interface User {
name: string
}
type UserList = Record<number, User>
const list: UserList = { 0: { name: 'Taro' }, 1: { name: 'Jiro' } }
console.log(list) //=> { '0': { name: 'Taro' }, '1': { name: 'Jiro' } }
Pick<T,K>
Pick<T,K>
は既に存在するT
型の中からK
で選択した一部のプロパティのみを含んだ新たな型を構築します。
下記の例では、Todo
のtitle
とcompleted
のみを含んだ新たな型TodoPreview
を作成しています。
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>
const preview: TodoPreview = {
title: '部屋の掃除',
completed: false,
}
console.log(preview) //=> { title: '部屋の掃除', completed: false }
Omit<T,K>
Omit<T,K>
は既に存在するT
型の中からK
で選択した一部のプロパティを除いた新たな型を構築します。
下記の例では、Todo
からdescription
を抜き取って、新たな型TodoPreview
を作成しています。
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = Omit<Todo, 'description'>
const preview: TodoPreview = {
title: '部屋の掃除',
completed: false,
}
console.log(preview) //=> { title: '部屋の掃除', completed: false }
Exclude<T,U>
Exclude はT
型のプロパティでU
型に代入可能なプロパティを取り除いた型を構築します。
下記の例では、
ExcludedType
では"id" | "name"
から"id" | "address"
に代入可能な"id"
を取り除いた型を作成しています。
ExcludedType2
ではstring
はnumber
に代入可能では無いので、string
となります。
ExcludedType3
ではstring | number | boolean
で唯一string | boolean
に代入可能では無いnumber
となります。
interface TypeA {
id: number
name: string
}
interface TypeB {
id: number
address: string
}
type ExcludedType = Exclude<keyof TypeA, keyof TypeB> // "name"
type ExcludedType2 = Exclude<string, number> // string
type ExcludedType3 = Exclude<string | number | boolean, string | boolean> // number
Extract<T,U>
Extract<T,U>
はExclude<T,U>
とは反対でT
型のプロパティでU
型に代入可能なプロパティのみを残した型を構築します。
下記の例では、
ExtractedType
では"id" | "name"
から"id" | "address"
に代入可能な"id"
のみ残した型を構築します。
ExtractedType2
では代入可能な型は存在しない無いので、never
となります。
ExtractedType3
ではstring | number | boolean
でstring | boolean
が代入可能なのでstring | boolean
となります。
interface TypeA {
id: number
name: string
}
interface TypeB {
id: number
address: string
}
type ExtractedType = Extract<keyof TypeA, keyof TypeB> // "id"
type ExtractedType2 = Extract<string, number> // never
type ExtractedType3 = Extract<string | number | boolean, string | boolean> // string | boolean
NonNullable<T>
NonNullable<T>
はT
からnull
とundefined
を取り除いた型を構築します。
下記の例では、
TypeA
はstring | number | undefined
からundefined
を取り除いた, string | number
になります。
TypeB
はstring[] | null | undefined
からnull | undefined
を取り除いた, string[]
になります。
type TypeA = NonNullable<string | number | undefined> // string | number
type TypeB = NonNullable<string[] | null | undefined> // string[]
Parameters<T>
Parameters<T>
は関数型T
の引数の型をタプル型として抽出した型を構築します。
const func = (text: string, num: number) => {
return `${text}${num}`
}
type TypeA = Parameters<typeof func> // [string, number]
ConstructorParameters<T>
ConstructorParameters<T>
はT
型のコンストラクタの引数の型をタプルとして抽出した型を構築します。
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
type TypeA = ConstructorParameters<typeof Person> // [string, number]
ReturnType<T>
ReturnType<T>
は関数型T
の戻り値の型を返します。
下記ではfunc2
の戻り値の型はnumber
なので、TypeA
はnumber
となります。
const func2 = (): number => 1
type TypeA = ReturnType<typeof func2> // number
ThisParameterType
関数型T
のthis
引数の型を抽出した型を構築します。
--strictFunctionTypes
が設定されている時のみ、期待通りの動きをします。詳細はこちら。
function toHex(this: Number) {
return this.toString(16)
}
type TypeA = ThisParameterType<typeof toHex> //Number
OmitThisParameter
関数型T
のthis
引数の型を取り除いた型を構築します。
下記の例ではTypeA
はtoHex
からthis
引数を除いた関数型()=> string
を返します。
--strictFunctionTypes
が設定されている時のみ、期待通りの動きをします。詳細はこちら。
function toHex(this: Number) {
return this.toString(16)
}
type TypeA = OmitThisParameter<typeof toHex> // () => string
ThisType<T>
ThisType<T>
を使用する事で、関数の中で参照されるthis
の型をT
とてコントロールする事ができます。
-noImplicitThis
がが設定されている必要があります。
interface User {
name: string
}
interface Greetings {
hello(): void
}
const user: Greetings & ThisType<User> = {
hello() {
console.log(`${this.name}です。`)
},
}
user.hello()
詳しくはstackoverflowのWhat is TypeScript's ThisType used for?でわかりやすく説明されていました。