はじめに
今回は、TypeScriptが提供する主要なユーティリティ型について解説します。
ユーティリティ型とは
ユーティリティ型(utility type)は、型から別の型を導き出してくれる型です。functionが実行時の世界の関数だとしたら、ユーティリティ型は型の世界の関数といったイメージです。
参照: サバイバルTypeScript
基本的に、ユーティリティ型<型>
という形で使用します。
ユーティリティ型を使いこなせるようになるのは、TypeScript初心者を抜け出すための重要なステップだと思いますので興味のある方はぜひ学習してみてください。
Required / Partial
Required
とPartial
は、オブジェクト型を受け取り、それぞれ全てのプロパティを必須にした型と、全てのプロパティを省略可能にした型を返します。
type User = {
name?: string;
age?: number;
};
type RequiredUser = Required<User>;
// type RequiredUser = {
// name: string;
// age: number;
// }
type PartialUser = Partial<RequiredUser>;
// type PartialUser = {
// name?: string | undefined;
// age?: number | undefined;
// }
(コメントアウト部はホバーしたときに表示される型です)
元々User型のプロパティは全て省略可能でしたが、Required
を使うことで全てのプロパティが必須になりました。また、そこに重ねる形でPartial
を使うことで全てのプロパティが省略可能になりました。
Readonly
Readonly
は、オブジェクト型を受け取り、全てのプロパティを読み取り専用にした型を返します。
type User = {
name: string;
age: number;
};
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = {
name: 'Taro',
age: 20,
};
// type ReadonlyUser = {
// readonly name: string;
// readonly age: number;
// }
user.name = 'Jiro'; // Error: Cannot assign to 'name' because it is a read-only property.
Readonly
を使うことで全てのプロパティが読み取り専用になりました。
その結果、user.name = 'Jiro';
のようにプロパティに値を代入しようとするとエラーが発生してくれるようになります。
注意点として、一定の条件下ではReadonly
を使ってもプロパティの書き換えが可能になることがあるので、注意が必要です。
参考: https://typescript-jp.gitbook.io/deep-dive/type-system/readonly
Record
Record
は、キーの型と値の型を受け取り、その型を持つ全てのプロパティを持つ型を返します。
キーの型はstring
やnumber
などのプリミティブ型、symbol
型とそれらのリテラル型を指定することができます。
type User = {
name: string;
age: number;
};
type UserRecord = Record<string, User>;
const users: UserRecord = {
'1': { name: 'Taro', age: 20 },
'2': { name: 'Jiro', age: 30 },
};
// type UserRecord = {
// [x: string]: User;
// }
type RGB = 'R' | 'G' | 'B';
type Color = Record<RGB, number>;
// type Color = {
// R: number;
// G: number;
// B: number;
// }
const color: Color = {
R: 255,
G: 255,
B: 255,
};
Pick / Omit
PickとOmitは、オブジェクト型を受け取り、それぞれ一部のプロパティを抽出した型と、一部のプロパティを除外した型を返します。
記法はPick<元の型, '抽出するプロパティ名'>
とOmit<元の型, '除外するプロパティ名'>
です。
type User = {
name: string;
age: number;
};
type UserName = Pick<User, 'name'>;
// type UserName = {
// name: string;
// }
type UserWithoutName = Omit<User, 'name'>;
// type UserWithoutName = {
// age: number;
// }
// リテラルを使って複数個のプロパティを指定することもできます
type PickNameAndAge = Pick<User, 'name' | 'age'>;
// type pickNameAndAge = {
// name: string;
// age: number;
// }
type OmitNameAndAge = Omit<User, 'name' | 'age'>;
// type OmitNameAndAge = {}
Exclude / Extract
Exclude
とExtract
は、ユニオン型を受け取り、それぞれ一部の型を除外した型と、一部の型を抽出した型を返します。
Pick / Omitのリテラル版と考えると理解しやすいかもしれません。
記法はExclude<元の型, 除外する型>
とExtract<元の型, 抽出する型>
です。
type Cats = '三毛猫' | '黒猫' | '白猫' | '茶トラ' | 'アメショ';
type NotBlackCats = Exclude<Cats, '黒猫'>;
// type NotBlackCats = "三毛猫" | "白猫" | "茶トラ" | "アメショ"
type BlackCats = Extract<Cats, '黒猫'>;
// type BlackCats = "黒猫"
type CatsWithoutBlackAndWhite = Exclude<Cats, '黒猫' | '白猫'>;
// type CatsWithoutBlackAndWhite = "三毛猫" | "茶トラ" | "アメショ"
type CatsOnlyBlackAndWhite = Extract<Cats, '黒猫' | '白猫'>;
// type CatsOnlyBlackAndWhite = "黒猫" | "白猫"
NonNullable
NonNullable
は、型を受け取り、その型からnull
とundefined
を除外した型を返します。
type UserName = string | null | undefined;
type NonNullableUserName = NonNullable<UserName>;
// type NonNullableUserName = string
ReturnType
ReturnType
は、関数型を受け取り、その関数の戻り値の型を返します。
type User = {
name: string;
age: number;
};
function createUser(name: string, age: number): User {
return { name, age };
}
type CreateUserReturnType = ReturnType<typeof createUser>;
// type CreateUserReturnType = {
// name: string;
// age: number;
// }
Awaited
Awaited
は、Promise型を受け取り、そのPromiseの中身の型を返します。
type User = {
name: string;
age: number;
};
type PromiseUser = Promise<User>;
// type PromiseUser = Promise<User>
type AwaitedPromiseUser = Awaited<PromiseUser>;
// type AwaitedPromiseUser = {
// name: string;
// age: number;
// }
Awaited
はReturnType
と組み合わせて使うことが多いです。
type User = {
name: string;
age: number;
};
async function fetchUser(): Promise<User> {
return { name: 'Taro', age: 20 };
}
// function fetchUser(): Promise<User>
type FetchUserAwaited = Awaited<ReturnType<typeof fetchUser>>;
// type FetchUserAwaited = {
// name: string;
// age: number;
// }
InstanceType
InstanceType
は、コンストラクタ関数型を受け取り、そのコンストラクタ関数のインスタンスの型を返します。
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
type UserInstance = InstanceType<typeof User>;
// type UserInstance = User
Parameters
Parameters
は、関数型を受け取り、その関数の引数の型をタプルで返します。
function createUser(name: string, age: number) {
return { name, age };
}
type CreateUserParameters = Parameters<typeof createUser>;
// type CreateUserParameters = [name: string, age: number]
UpperCase / LowerCase
UpperCase
とLowerCase
は、文字列型を受け取り、その文字列を大文字にした型と小文字にした型を返します。
type UppercaseName = Uppercase<'taro'>;
// type UppercaseName = "TARO"
type LowercaseName = Lowercase<'TARO'>;
// type LowercaseName = "taro"
Capitalize / Uncapitalize
Capitalize
とUncapitalize
は、文字列型を受け取り、その文字列の最初の文字を大文字にした型と小文字にした型を返します。
type CapitalizedName = Capitalize<'taro'>;
// type CapitalizedName = "Taro"
type UncapitalizedName = Uncapitalize<'Taro'>;
// type UncapitalizedName = "taro"
おわりに
最後まで読んでいただきありがとうございます!
TypeScriptのユーティリティ型は、型を操作するための非常に強力な機能です。
ぜひ、これらのユーティリティ型を使って普段のコーディングを効率化してみてください!
参考