【入門編】 Record – TypeScript実践ガイド

こんにちは!フロントエンド・アーキテクチャの世界へようこそ。
日々、TypeScriptと向き合っていると、「もっとスマートに型を定義したい!」とか「同じようなオブジェクトの型を何度も書くの、正直めんどくさいな…」と感じる瞬間が必ずやってきます。

今回は、そんなモヤモヤを鮮やかに解消してくれる魔法のユーティリティ型、`Record` について、現場のリアルな視点も交えながら、うんと優しく、そして深く紐解いていきたいと思います。

TypeScriptを触り始めたばかりの頃って、見慣れない記号や構文の連続で、画面を見るだけでも肩が凝っちゃいますよね。「あ、またエラーが出た…」なんて落ち込む必要は全くありません。一つひとつ、身近な例えから紐解いていけば、必ず「なるほど!」と腑に落ちる瞬間が来ますから、どうぞリラックスしてついてきてくださいね。

—

1. `Record` って、一体なんだろう?

まずは、堅苦しい定義は置いておいて、イメージから膨らませてみましょう。

日常のお買い物で、こんな「ラベル付きの引き出し」を想像してみてください。

  • 引き出しの「名前(キー)」が決まっている。
  • その中に入れる「中身(値)」のルールも決まっている。

例えば、「月曜日から日曜日までの曜日(キー)」というラベルが貼られた7つの引き出しがあって、その中にはすべて「その日の予定を表す文字列(値)」を入れる、といった具合です。

この「キーの種類」と「値の種類」をパパッと指定して、一瞬で綺麗なお片付けボックス(オブジェクト型)を作ってくれるのが、`Record` の正体です。

公式ドキュメント的な言い方をすると「キーが `K` で、値が `T` であるオブジェクトの型を生成するユーティリティ型」となりますが、要するに「キーと値の型をセットでまとめて定義するショートカット」だと思ってください。

—

2. なぜ `Record` を使うの?(ビフォーアフターで見る恩恵)

「別に、普通のオブジェクト型で書けるじゃん」って思いますよね?
確かにその通りなんです。でも、コードの規模が大きくなったり、データの構造を変更したくなったりしたとき、`Record` の真価が発揮されます。

ちょっと、よくある「ユーザーの権限管理」を例に見てみましょう。

従来の書き方(ちょっと泥臭い方法)

// ユーザーの役割ごとに、それぞれ持っているフラグを管理したい
type Permissions = {
admin: boolean;
editor: boolean;
viewer: boolean;
};

これでも動きます。動きますが、もしここに「ゲスト(guest)」という役割を追加することになったらどうでしょう? 型の定義をわざわざ書き換えにいかなくてはなりません。

`Record` を使ったスマートな書き方

これを `Record` を使って書き換えてみると、こうなります。

// 役割の種類をunion型(または文字列リテラル)で定義
type Role = ‘admin’ | ‘editor’ | ‘viewer’;

// Recordを使うと、役割ごとのboolean型オブジェクトが瞬時に完成する!
type Permissions = Record;

どうでしょう? `Record` と書くことで、「`Role` に含まれるすべての文字をキーにして、それぞれの値は `boolean` にしてね!」という指示をTypeScriptに一発で伝えることができます。

もし後から「やっぱり `guest` も追加しよう!」となったときも、`Role` の方に `’guest’` を付け足すだけで、`Permissions` 型も自動的にアップデートされます。この連動感、実務では本当にありがたい神機能なんです。

—

3. 実務でよくあるシチュエーションで使ってみよう

では、もう少し具体的なコードで、日々のWeb制作やアプリ開発でどうやって `Record` が使われているのかを見ていきましょう。
エディタを開いたつもりで、じっくり読んでみてくださいね。

パターンA:設定画面のテーマカラー管理

例えば、Webサイトのテーマ(ダークモードやライトモードなど)ごとに、使う色をまとめたオブジェクトを作るとします。

// テーマの種類
type ThemeType = ‘light’ | ‘dark’ | ‘sepia’;

// 各テーマが持つカラー情報の構造
type ThemeColors = {
background: string;
text: string;
primary: string;
};

// Recordを使って、「テーマ名」をキーにした「カラー情報」のオブジェクト型を作る
const siteThemes: Record = {
light: {
background: ‘#ffffff’,
text: ‘#333333’,
primary: ‘#007bff’,
},
dark: {
background: ‘#1a1a1a’,
text: ‘#f5f5f5’,
primary: ‘#bb86fc’,
},
sepia: {
background: ‘#f4ecd8’,
text: ‘#5c4033’,
primary: ‘#8b4513’,
},
};

// 【ここが安心ポイント!】
// もし、うっかり “sepia” の定義を書き忘れたりすると、
// TypeScriptが「おいおい、sepiaの設定が足りないよ!」と赤く波線を出して教えてくれます。

うっかり屋さんの私たちを、TypeScriptのコンパイラが後ろから優しくハグして守ってくれるような感覚です。これならミスを未然に防げますよね。

—

パターンB:APIのエラーメッセージ集

フロントエンド開発で避けて通れないのが、サーバーからのエラーハンドリングです。エラーコードごとに、ユーザーに見せるメッセージをマッピングしてみましょう。

// エラーコードの定義
type ErrorCode = ‘400’ | ‘401’ | ‘403’ | ‘404’ | ‘500’;

// エラーメッセージのマップ型をRecordで作る
type ErrorMessages = Record;

const apiErrorMessages: ErrorMessages = {
‘400’: ‘リクエストの内容が正しくありません。’,
‘401’: ‘認証されていません。ログインし直してください。’,
‘403’: ‘アクセス権限がありません。’,
‘404’: ‘お探しのページが見つかりませんでした。’,
‘500’: ‘サーバー側でエラーが発生しました。しばらくお待ちください。’,
};

// 使うときはこんな感じ
function getMessage(code: ErrorCode): string {
return apiErrorMessages[code];
}

console.log(getMessage(‘404’)); // 「お探しのページが見つかりませんでした。」が出力される

キーのタイポ(打ち間違い)も完全に防げますし、「どのエラーコードに対してメッセージを用意すべきか」が一目でわかるドキュメント代わりにもなります。

—

4. つまずきやすいポイントと、優しくなれる処方箋

ここで、初学者の人が `Record` を使っていて「あれっ?」とつまずきがちなポイントをこっそりシェアしておきますね。

つまずきポイント:

> 「Recordのキーに、何でもかんでも適当な文字列を入れようとしてエラーになる…」

処方箋:

`Record` の第一引数 `K` には、「具体的なキーのリスト(リテラル型やunion型)」を渡してあげるのが基本です。

もし「どんな文字列が来るか分からないけど、とにかくキーは文字列で、値は数値のオブジェクトを作りたい!」という場合は、`Record` よりも、インデックスシグネチャという別の書き方を使う方が自然なケースが多いです。

// どんな文字列のキーでも受け付けたい場合の書き方(インデックスシグネチャ)
type AnyStringKeyObject = {
[key: string]: number;
};

「あ、厳密にキーのパターンが決まっているときは `Record`、キーが自由奔放に増える可能性があるときは別の方法」と頭の片隅に置いておくだけで、コードを書くときの迷いがぐっと減りますよ。

—

さいごに

お疲れ様でした!
`Record` のイメージ、少しずつ掴めてきたでしょうか?

最初は「なんだか難しそうな名前だな…」と感じるユーティリティ型も、こうして身近な例えや実際のユースケースに落とし込んでみると、実は私たちの開発をそっと助けてくれる心強い相棒であることが分かります。

TypeScriptの型定義に正解は一つではありませんが、少しでもコードがスッキリして、あなたの開発ライフが楽しくなるなら、それが一番の正解です。

今日からあなたのコードにも、ぜひ `Record` を取り入れてみてくださいね。
「あ、ここも Record でスマートに書けるかも!」と思いついた瞬間から、あなたのTypeScriptスキルは確実にワンランクアップしていますよ。大丈夫、一歩ずつ楽しく進んでいきましょう!

コメント

タイトルとURLをコピーしました