TypeScript Readonly<T>ユーティリティ型の解説

Readonly<T>が型レベルですべてのプロパティをイミュータブルにする方法を学びます。フリーズされたオブジェクト、Reduxの状態、イミュータブルデータパターンの例を含みます。

Object Types

詳細な説明

Readonlyの理解

Readonly<T>Tのすべてのプロパティをreadonlyに設定した型を構築します。結果の型のプロパティは初期化後に再代入できません。

構文

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

基本的な例

interface Point {
  x: number;
  y: number;
}

type ReadonlyPoint = Readonly<Point>;
// 以下と同等:
// {
//   readonly x: number;
//   readonly y: number;
// }

const p: ReadonlyPoint = { x: 10, y: 20 };
// p.x = 5; // エラー: 読み取り専用プロパティ'x'に代入できません

Object.freeze()との関係

Readonly<T>Object.freeze()の型レベルの等価物です:

function freeze<T extends object>(obj: T): Readonly<T> {
  return Object.freeze(obj);
}

const config = freeze({ host: "localhost", port: 3000 });
// config.port = 8080; // エラー!

シャローReadonlyとディープReadonly

Partialと同様に、Readonlyはシャロー(浅い)です。ネストされたオブジェクトは依然として変更可能です:

interface State {
  user: { name: string; age: number };
  items: string[];
}

type ReadonlyState = Readonly<State>;
const state: ReadonlyState = { user: { name: "A", age: 1 }, items: [] };
// state.user = { name: "B", age: 2 }; // エラー
state.user.name = "B"; // OK!(ネストされた変更)

深いイミュータビリティにはカスタムのDeepReadonly型またはas constが必要です。

ユースケース

Readonly<T>はReduxの状態型、フリーズされた設定オブジェクト、イミュータブルデータパターン、変更されるべきでないイベントペイロード、変更されるべきでない関数パラメータに使用します。

試してみる — TypeScript Utility Types

フルツールを開く