【入門編】配列の要素を型として抽出する:typeofとインデックスアクセス型の応用 – TypeScript コア・型システムの基礎解析バイブル

こんにちは、現場を支えるフルスタックエンジニアです。

TypeScriptの世界へようこそ。これから皆さんは、単なる「JavaScriptに型をつけたもの」という認識を超えて、「型でロジックを制御する」という本当のTypeScriptの面白さに触れることになります。

今日お話しするのは、中級者への階段を登る際に誰もが「おお、これは便利だ!」と感動する魔法のようなテクニック。「配列の要素から自動的に型を作る」方法です。

「配列の中身を増やしたのに、型定義を修正し忘れてエラーになった…」

そんな二度手間(ダブルメンテナンス)の悩みとは、今日でサヨナラしましょう。

—

1. なぜ「配列から型を作る」必要があるのか?

例えば、SNSアプリの「投稿の公開設定」を作っていると想像してください。

// 1. 公開範囲の種類を配列で定義
const visibilityOptions = [‘public’, ‘private’, ‘followers’];

// 2. 「公開範囲」としての型も欲しい
type Visibility = ‘public’ | ‘private’ | ‘followers’;

一見、普通ですよね。でも、ここに新しく `’close-friends’`(親しい友人のみ)を追加したくなったらどうでしょう?

配列に足して、型定義にも足して……。もし片方を忘れたら、プログラムは予期せぬ動きをします。この「同じ情報を2箇所に書く」ことこそが、バグの温床です。

そこで、「配列を唯一の正解(Single Source of Truth)にして、型はそこから自動抽出する」のがスマートなやり方です。

—

2. 魔法の呪文:`as const`(常数化)

まず、準備として最も重要なのが `as const` です。

// 普通の配列定義(型推論は string[] になる)
const fruits = [‘apple’, ‘banana’, ‘orange’];

// 魔法の「as const」をつけた定義
const COLORS = [‘red’, ‘blue’, ‘green’] as const;

TypeScriptは通常、配列の中身を「いつか書き換わるもの」として扱い、型を広めに(`string[]`など)推論します。しかし、`as const` をつけると、「この配列は、この順番で、この値以外絶対に受け入れない!」というガチガチのリテラル型(値そのものの型)として扱ってくれるようになります。

—

3. `typeof` と `[number]` の合わせ技

ここからが本番です。定義した配列から、ユニオン型(`’red’ | ‘blue’ | ‘green’`)を取り出してみましょう。

const COLORS = [‘red’, ‘blue’, ‘green’] as const;

/

  • 究極の1行:配列の要素を型として抽出する

/
type Color = (typeof COLORS)[number];

// 結果、Color型はこうなります:
// type Color = “red” | “blue” | “green”;

このコードで何が起きているのか?(分解解説)

1. `typeof COLORS`

  • 「値」である `COLORS` 変数を、「型」の世界へ持ち込みます。`as const` のおかげで、型は `readonly [“red”, “blue”, “green”]` という非常に具体的な形になっています。

2. `[number]`

  • これは「インデックスアクセス型」と呼ばれます。
  • 「配列のインデックス(0, 1, 2…)が `number` であるすべての要素の型をください」とお願いしているイメージです。
  • すると、TypeScriptは律儀に「0番目の ‘red’、1番目の ‘blue’、2番目の ‘green’……全部まとめてユニオン型にしますね!」と返してくれるのです。

—

4. 実戦で使える具体例

実際の開発現場では、UIコンポーネントのProps(引数)の定義などでよく使われます。

// 1. マスターデータを定義(ここが唯一の正解)
const BUTTON_TYPES = [‘primary’, ‘secondary’, ‘danger’] as const;

// 2. 型を自動生成
type ButtonType = (typeof BUTTON_TYPES)[number];

// 3. 関数で利用
function createButton(label: string, type: ButtonType) {
console.log(`Creating a ${type} button named ${label}`);
}

// 実行例
createButton(‘保存’, ‘primary’); // OK
createButton(‘削除’, ‘danger’); // OK

// @ts-expect-error: 定義にない値を入れるとコンパイルエラーになる
createButton(‘エラー’, ‘unknown’);

このようにしておけば、将来 `BUTTON_TYPES` に `’ghost’` を追加するだけで、`ButtonType` 型も自動的に更新されます。開発者は配列をメンテナンスするだけでいい。これぞ「掌握」している感覚ですよね。

—

5. 陥りやすいミスと注意点

`as const` を忘れるとどうなる?

もし `as const` を忘れると、`typeof COLORS` はただの `string[]` になります。
その状態で `[number]` を使うと、型は単なる `string` になってしまいます。

const badArray = [‘a’, ‘b’]; // as const がない
type BadType = (typeof badArray)[number]; // 結果は string 型(’a’ | ‘b’ ではない)

これでは特定の文字列だけに制限するメリットが消えてしまいます。「配列から型を抜くときは `as const` とセット」と覚えておきましょう。

—

まとめ:TypeScriptを味方につける第一歩

今回紹介した手法は、TypeScriptの強力な推論機能を最大限に活かすための基礎体力のひとつです。

  • `as const` で値を型の中に閉じ込める。
  • `typeof` で値の世界から型の世界へアクセスする。
  • `[number]` で配列の全要素をユニオン型として回収する。

この流れをマスターすれば、あなたの書くコードはより堅牢になり、リファクタリングも驚くほど楽になります。

「ここをクリアすれば、TypeScriptの基本はバッチリマスターできますよ」

一歩ずつ、楽しみながらコードを書いていきましょう。次は、この応用編として「オブジェクトのキーから型を作る方法」なども面白いですよ。また次回の記事でお会いしましょう。

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