TypeScriptによる静的型付け言語入門④ 『Utilty Types』
こんにちは!
スマレジ テックファームのMichiです!
今回はTypeScriptのUtility Typesについて整理します。
Utility Typesとは?
Utility Typesは、既存の型を新しい型に変換するための便利なツールです。例えば、あるオブジェクト型のすべてのプロパティを読み取り専用にする、オプションのプロパティを必須にする、のようなことができます。Utility Typesは「型の世界の関数」という表現をされることもあります。
Utility Typesを使うことで、繰り返し同じような型定義を書く手間を省き、コードの保守性を向上させることができます。
代表的なUtility Types
それでは、具体的なUtility Typesについて見ていきましょう。
Readonly
Readonly<T>
はT
に与えられたオブジェクト型のすべてのプロパティを読み取り専用にします。これは、あるオブジェクトが後で変更されることを防ぎたい場合に便利です。
例えば、次のようなStudent
オブジェクトの場合を考えてみましょう。
type Student = { name: string; age: number; }; const john: Readonly<Student> = { name: "John", age: 15 }; john.name = "Amy" // エラー: Cannot assign to 'name' because it is a read-only property.
Student
はもともと、プロパティの書き換えを許容するオブジェクト型ですが、Readonly
を使って読み取り専用の型として定義しなおします。これでjohn
の情報を変更しようとすると、TypeScriptがエラーを出してくれます。
Partial
Partial<T>
はT
に与えられたオブジェクト型のすべてのプロパティをオプショナルにします。これは、すべてのプロパティを必要としない場合に便利です。
type Student = { name: string; age: number; }; const john: Partial<Student> = { name: "John" };
Student
型にはname
とage
の両プロパティが必要ですが、Partical
を使用するとage
がなくてもエラーになりません。
Required
Required<T>
はPartical
の反対です。T
に与えられたオブジェクト型のすべてのプロパティを必須にします。
type OptionalStudent = { name?: string; age?: number; }; const john: Required<OptionalStudent> = { name: "John" }; // エラー: Property 'age' is missing in type '{ name: string; }' but required in type 'Required<OptionalStudent>'.
OptionalStudent
型のname
とage
ともにオプショナルなプロパティですが、Required
を使用すると両プロパティともに必須となります。したがって上のようにage
がないオブジェクトはエラーです。
Pick
Pick<T, K>
はT
に与えられたオブジェクト型からK
で指定したプロパティのみを抽出した新しい型を作ります。
type Student = { name: string; age: number; }; // Student型からnameのみを抽出する const john: Pick<Student, "name"> = { name: "John" };
なお、K
の部分に複数のプロパティを指定したい場合は、次のようにユニオン型を使います。
type Student = { name: string; age: number; height: number; }; // Student型からnameとageのみを抽出する const john: Pick<Student, "name" | "age"> = { name: "John", age: 15 };
Omit
Omit<T, K>
はPick
の反対です。T
に与えられたオブジェクト型からK
で指定したプロパティを除外して新しい型を作ります。
type Student = { name: string; age: number; }; // Student型からageのみを除外する const john: Omit<Student, "age"> = { name: "John" };
Pick
のときと同じく、K
の部分に複数のプロパティを指定したい場合はユニオン型を使います(例は省略)。
Extract
Extract<T, U>
は、T
の構成要素のうちのU
に含まれる型(部分型)を抽出した新しい型を作ります。
type Numbers = 1 | 2 | 3 | 4; type Even = 2 | 4 | 6; type EvenNumbers = Extract<Numbers, Even>; // EvneNumger型は 2 | 4
Exclude
Exclude<T, U>
はExtract
の反対です。T
の構成要素のうちのU
に含まれる型(部分型)を取り除いた新しい型を作ります。
type Numbers = 1 | 2 | 3 | 4; type Even = 2 | 4 | 6; type OddNumbers = Exclude<Numbers, Even>; // OddNumbers型は 1 | 3
NonNullable
NonNullable
タイプはnull
またはundefined
を除外します。
type NullableString = string | null | undefined; type StringOnly = NonNullable<NullableString>; // StringOnly型は string
Record
最後はRecord
タイプです。Record<K, T>
はプロパティのキーがK
であり、値がT
であるオブジェクトの型を作ります。
type ScoreRecord = Record<string, number>; const johnScores: ScoreRecord = { math: 90, english: 85 };
K
の部分はリテラルのユニオン型で表現することができます。
type ScoreRecord = Record<"math" | "english", number>; const johnScores: ScoreRecord = { math: 90, english: 85, science: 70 }; // エラー: Type '{ math: number; english: number; science: number; }' is not assignable to type 'ScoreRecord'. // Object literal may only specify known properties, and 'science' does not exist in type 'ScoreRecord'.
こうすることで、johnScores
はmath
とenglish
以外のプロパティを許可しない型になります。
その他にも多くのUtility Typeが存在します。ここでは説明しきれませんが、興味のある方は公式ドキュメントを参照してみてください。
まとめ
TypeScriptのUtility Typesについてのまとめでした。
今回でいったんTypeScriptのキャッチアップは終了にしたいと思います。
最初はJavaScriptに型が付いただけの言語かと思っていましたが、そのことによりTypeScript独特の機能が増え、なかなか奥深いな思いました。 静的型付け言語初体験の自分にとっては理解づらい概念も多かったですが、その分新しい発見も多く、楽しんで学習することができました。
では、このへんで。ここまでお読みいただきありがとうございました。