はじめに
こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。
TypeScript ではオブジェクトの型を表現する方法がいくつかあります。その中でも柔軟に使えるのが Record<K, T> というユーティリティ型です。
- キーが決まっているオブジェクト
- 動的にキーが増減するオブジェクト
どちらにも使える便利な型ですが、any や unknown との違いが分かりづらいと感じる方も多いと思います。この記事では、Record 型の基本から実例、注意点まで まとめます。
Record 型とは?
Record<K, T> は「キーが K 型・値が T 型のオブジェクト」を表します。
type Record<K extends keyof any, T> = {
[P in K]: T;
};
-
K … キーの型(
string,number,symbolなど) - T … 値の型
例:文字列キーと数値の値
const scores: Record<string, number> = {
math: 90,
english: 85,
science: 92,
};
Record<string, unknown> の使いどころ
unknown を使うことで、値が「まだ型不明」であることを明示できます。
1. API レスポンスの仮受け
外部 API のレスポンス型が未確定な場合、一旦 Record<string, unknown> で受けて後から型ガードする方法です。
function handleApiResponse(data: Record<string, unknown>) {
if (typeof data.name === 'string') {
console.log(`名前: ${data.name}`);
}
}
2. 動的なフォームデータ
フォームのフィールドが動的に変化する場合に便利です。
type FormData = Record<string, unknown>;
const form: FormData = {
name: 'Taira',
age: 28,
agree: true,
};
if (typeof form.age === 'number') {
console.log(form.age + 1); // 29
}
unknown と any の違い
-
any- どんな操作も許される → 型安全性がない
-
unknown- 型チェックが必須 → 安全に扱える
// any: 直接アクセス可能(危険)
const obj1: Record<string, any> = {};
obj1.foo.bar(); // エラーにならない
// unknown: 型ガード必須(安全)
const obj2: Record<string, unknown> = {};
// obj2.foo.bar(); // エラー
これらの詳細について記事を書いているのでそちらをご確認ください
値の型が確定している場合は専用型を使う
もし値の型が分かっているなら、専用型を定義する方が読みやすいです。
type User = {
name: string;
age: number;
};
const users: Record<string, User> = {
taira: { name: 'Taira', age: 28 },
ken: { name: 'Ken', age: 30 },
};
まとめ
-
Record<K, T>はキーと値の型を指定できる便利なユーティリティ型 -
Record<string, unknown>は「キーが文字列・値が不明」なときに使う -
unknownはanyより安全だが、型ガードが必要 - 値の型が決まっている場合は専用型を使う方が可読性が高い
さらに発展
-
Record<string, unknown>と型スキーマバリデーション(Zod, Yup)を組み合わせる -
Partial<Record<K, T>>やReadonly<Record<K, T>>など他のユーティリティ型と併用する