TypeScript PR

TypeScriptのRecord型とは?完全ガイド

記事内に商品プロモーションを含む場合があります

TypeScriptには便利なユーティリティ型が数多く存在します。その中でもRecord<K, T>型は、オブジェクトのキーと値の型を厳密に定義できる強力な型です。本記事では、Record型の基本から、具体的な使い道、注意点、応用例まで詳しく解説します。


Record型とは?

基本の定義

Record<K, T>型は、キーKの型と値Tの型を指定し、それらを持つオブジェクトを作成するための型です。

type Record<K extends keyof any, T> = {
  [P in K]: T;
};

つまり、Record<K, T>は次のようなオブジェクトを表します。

  • K:オブジェクトのキーの型(string | number | symbolのいずれか)
  • T:キーに対応する値の型

基本的な使い方

例えば、ユーザーIDをキーとし、ユーザー名を値とするオブジェクトを作成する場合、Record型を次のように定義できます。

type UserRecord = Record<number, string>;

const users: UserRecord = {
  1: "Alice",
  2: "Bob",
  3: "Charlie"
};


インデックス型との違い

TypeScriptにはRecord<K, T>型のほかにも「インデックス型」と呼ばれるものがあります。インデックス型とRecord型の違いを理解することは重要です。

インデックス型とは?

インデックス型は、任意のキーを持つオブジェクトの型を定義する方法です。

type IndexType = {
  [key: string]: number;
};

const data: IndexType = {
  apple: 10,
  banana: 20,
  cherry: 30,
};

Record型との違い

キーの制限値の制限用途
Record<K, T>Kは指定した型のみTは指定した型のみ事前に決まったキーを持つオブジェクトの型定義
インデックス型任意のキー (stringnumber)指定した型の値任意のキーを持つオブジェクトの型定義

例えば、Record<"apple" | "banana", number>applebananaのキーしか持てませんが、インデックス型なら他のキーも追加可能です。

// Record型
const recordData: Record<"apple" | "banana", number> = {
  apple: 10,
  banana: 20,
  // cherry: 30, // エラー!
};

// インデックス型
const indexData: { [key: string]: number } = {
  apple: 10,
  banana: 20,
  cherry: 30, // OK
};


Record型の使い道

オブジェクトのマッピング

Record<K, T>は、ユニオン型のキーを持つオブジェクトを型安全に定義できます。

type Role = "admin" | "editor" | "viewer";

const permissions: Record<Role, boolean> = {
  admin: true,
  editor: true,
  viewer: false,
};

オブジェクトの形状を制限する

オブジェクトのキーを限定し、値の型を保証する用途にも利用できます。

type Config = Record<"theme" | "language", string>;

const settings: Config = {
  theme: "dark",
  language: "en",
};

動的なキーのマッピング

キーが動的に決まる場合にもRecord型を活用できます。

type UserID = number;
type UserInfo = { name: string; age: number };

const users: Record<UserID, UserInfo> = {
  1: { name: "Alice", age: 25 },
  2: { name: "Bob", age: 30 },
};


Record型の内部

Record<Keys, Type>の型引数

Keys

  • Record<K, T>Kは、オブジェクトのキーの型を表します。
  • string | number | symbolのいずれかである必要があります。
type KeysExample = Record<"id" | "name", string>;

Type

  • Record<K, T>Tは、キーに対する値の型を表します。
  • プリミティブ型、オブジェクト型、配列型など、あらゆる型を指定できます。
type ValuesExample = Record<string, { id: number; name: string }>;

Record型の応用例

Record型を関数の引数として使用

Record型を引数に持つ関数を定義できます。

function printUsers(users: Record<number, string>) {
  for (const id in users) {
    console.log(`ID: ${id}, Name: ${users[id]}`);
  }
}

const users = { 1: "Alice", 2: "Bob" };
printUsers(users);

Record型とマッピング型の組み合わせ

マッピング型と組み合わせることで、より柔軟な型を作成できます。

type UserRoles = "admin" | "user";
type UserPermissions = Record<UserRoles, boolean>;

const permissions: UserPermissions = {
  admin: true,
  user: false,
};


注意点と対処法

型安全性の限界

Record<K, T>型は、オブジェクトのキーが固定されるため、動的に追加・削除する際の型安全性が低下する場合があります。

const data: Record<string, number> = {};
data["newKey"] = 123; // OK(ただし、型チェックは緩くなる)

undefinedリスクに注意

オブジェクトのキーが確実に存在する保証はないため、undefinedになるリスクがあります。

const users: Record<number, string> = { 1: "Alice", 2: "Bob" };
console.log(users); // undefined(キーが存在しない)

対策: Optional Chainingin演算子を使う。

if (3 in users) {
  console.log(users);
}

まとめ

  • Record<K, T>型は、オブジェクトのキーと値の型を厳密に定義できる便利な型。
  • インデックス型とは異なり、キーを特定の型に制限できる。
  • 設定値、マッピング、動的なキーの管理など幅広い場面で役立つ。
  • ただし、undefinedのリスクや動的なキーの追加には注意が必要。