TypeScriptでプロパティのOptional(省略可能)とReadonly(読み取り専用)の使い方について、実践的な例を交えながら解説します。

Optionalプロパティ(省略可能なプロパティ)

Optionalプロパティは、そのプロパティが必須ではないことを示します。プロパティ名の後に`?`を付けることで指定できます。

interface User {
  name: string;      // 必須
  age?: number;      // 省略可能
  email?: string;    // 省略可能
}

// 正常に動作する例
const user1: User = {
  name: "John"
  // age と email は省略可能なので指定しなくてもOK
};

const user2: User = {
  name: "Alice",
  age: 25,
  email: "alice@example.com"
};

Readonlyプロパティ(読み取り専用プロパティ)

Readonlyプロパティは、一度値を設定すると変更できないプロパティを定義します。`readonly`キーワードを使用します。

interface Config {
  readonly apiKey: string;
  readonly baseUrl: string;
  timeout?: number;
}

const config: Config = {
  apiKey: "abc123",
  baseUrl: "https://api.example.com"
};

// エラー: readonly プロパティは変更できない
// config.apiKey = "xyz789";

Optional と Readonly の組み合わせ

OptionalとReadonlyは組み合わせて使用することもできます:

interface Settings {
  readonly id: number;
  readonly name: string;
  readonly description?: string;  // 省略可能かつ読み取り専用
}

const settings: Settings = {
  id: 1,
  name: "Default Settings"
};

ユースケース

フォームデータの型定義

interface FormData {
  username: string;           // 必須
  password: string;          // 必須
  readonly id?: string;      // 自動生成されるID(省略可能・読み取り専用)
  phoneNumber?: string;      // 省略可能な電話番号
}

APIレスポンスの型定義

interface APIResponse {
  readonly status: number;          // HTTPステータスコード
  readonly data: object;           // レスポンスデータ
  readonly timestamp?: number;     // タイムスタンプ(省略可能)
}

注意点と技術的な詳細

1. Readonlyは浅い(shallow)イミュータビリティのみを提供します:

interface NestedObject {
  readonly user: {
    name: string;
    age: number;
  }
}

const obj: NestedObject = {
  user: { name: "John", age: 30 }
};

// これはエラーにならない(ネストされたオブジェクトは変更可能)
obj.user.name = "Jane";

// これはエラーになる(トップレベルのプロパティは変更不可)
// obj.user = { name: "Jane", age: 25 };

2. 型アサーションとの併用:

interface ReadonlyUser {
  readonly id: number;
  readonly name: string;
}

// as constを使用して、オブジェクトリテラルを完全な読み取り専用にする
const user = {
  id: 1,
  name: "John"
} as const;

これらの機能を適切に使用することで、より堅牢なTypeScriptコードを書くことができます。Optionalプロパティは柔軟性を提供し、Readonlyプロパティはイミュータビリティを確保するのに役立ちます。

まとめ

  • `?`を使用してOptionalプロパティを定義
  • `readonly`キーワードでReadonlyプロパティを定義
  • 両者は組み合わせて使用可能
  • Readonlyは浅いイミュータビリティのみを提供
  • 適切な使用でコードの安全性と柔軟性が向上

これらの機能を活用することで、型安全性が高く、メンテナンス性の良いTypeScriptコードを書くことができます。