Michi's Tech Blog

一人前のWebエンジニアを目指して

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型にはnameageの両プロパティが必要ですが、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型のnameageともにオプショナルなプロパティですが、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'.

こうすることで、johnScoresmathenglish以外のプロパティを許可しない型になります。


その他にも多くのUtility Typeが存在します。ここでは説明しきれませんが、興味のある方は公式ドキュメントを参照してみてください。

www.typescriptlang.org

まとめ

TypeScriptのUtility Typesについてのまとめでした。

今回でいったんTypeScriptのキャッチアップは終了にしたいと思います。

最初はJavaScriptに型が付いただけの言語かと思っていましたが、そのことによりTypeScript独特の機能が増え、なかなか奥深いな思いました。 静的型付け言語初体験の自分にとっては理解づらい概念も多かったですが、その分新しい発見も多く、楽しんで学習することができました。

では、このへんで。ここまでお読みいただきありがとうございました。