Skip to content

マップ型(Mapped Types)

マップ型は、TypeScriptの強力な機能の一つで、既存の型を基にして新しい型を生成するために使用されます。ある型の各プロパティを反復処理し、それらを新しい方法で変換することで、DRY(Don't Repeat Yourself)の原則に従った、保守性の高いコードを書くのに役立ちます。

基本構文

マップ型の基本的な構文は、[P in K] という形式です。ここで K は通常、keyof T のようなキーの集合を表す型です。

typescript
type MappedType<T> = {
  [P in keyof T]: T[P]; // Tの各プロパティPに対して、型T[P]を持つプロパティを定義
};

標準ユーティリティ型の実装例

TypeScriptに組み込まれている多くのユーティリティ型は、マップ型を使用して実装されています。

Readonly<T>

Readonly<T> は、型 T のすべてのプロパティを読み取り専用(readonly)にします。

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

interface User {
  name: string;
  age: number;
}

const readonlyUser: Readonly<User> = {
  name: "John",
  age: 30,
};

// Error: Cannot assign to 'name' because it is a read-only property.
// readonlyUser.name = "Jane";

Partial<T>

Partial<T> は、型 T のすべてのプロパティをオプショナル(?)にします。

typescript
type Partial<T> = {
  [P in keyof T]?: T[P];
};

const partialUser: Partial<User> = {
  name: "John", // ageはなくてもOK
};

マッピング修飾子(Mapping Modifiers)

マップ型では、readonly? といった修飾子を追加または削除できます。+- をプレフィックスとして使用します。+ はデフォルトなので、通常は省略されます。

? 修飾子の削除

例えば、すべてのプロパティを必須にする Required<T> は、-? を使用して実装されます。

typescript
type Required<T> = {
  [P in keyof T]-?: T[P];
};

interface PartialUser {
  name?: string;
  age?: number;
}

// { name: string; age: number; } と同じ型になる
type RequiredUser = Required<PartialUser>;

キーの再マッピング(Key Remapping via as

マップ型では as 句を使用して、プロパティ名を変更することも可能です。これにより、さらに柔軟な型変換が実現できます。

例:Getterメソッドの型を生成

オブジェクトの各プロパティに対して、get<PropertyName> という形式のgetterメソッドを持つ新しい型を生成する例です。

typescript
type Getter<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

interface Person {
  name: string;
  age: number;
}

// { getName: () => string; getAge: () => number; } という型になる
type PersonGetters = Getter<Person>;

この例では、Capitalize ユーティリティ型とテンプレートリテラル型を組み合わせて、プロパティ名を name から getName に変換しています。

マップ型は、型の変換や再利用性を高めるための非常に強力なツールであり、高度な型定義を行う上で不可欠な機能です。

AI が自動生成した技術記事をまとめたテックブログ