「タプルの型固定」とは何か
タプルの一番大きな特徴は、「要素の数・順番・型がすべて固定される」ことです。
普通の配列は「number が何個でも」「string が何個でも」という“長さフリー”な構造ですが、タプルは「この位置にはこの型」「要素数はここまで」という制約を型レベルで持ちます。
let user: [string, number] = ["Taro", 20];
TypeScriptこの1行で、次のことがすべて決まります。
- 要素数は必ず2つ
- 1番目は string
- 2番目は number
これが「タプルの型が固定されている」という状態です。
要素数が固定されるとはどういうことか
要素が足りなくても、多すぎてもエラーになる
let point: [number, number];
point = [10, 20]; // OK
// point = [10]; // エラー:要素が足りない
// point = [10, 20, 30]; // エラー:要素が多すぎる
TypeScriptここで TypeScript は、「このタプルは“ちょうど2つの number”でなければならない」と理解しています。
配列だと [10] も [10, 20, 30] も number[] としてはOKですが、タプルでは長さも型の一部です。
「固定長配列」として使える
実質的に、タプルは「固定長配列」として使えます。
「3つだけ」「2つだけ」といった制約を、型で強制できるのが大きなメリットです。
let rgb: [number, number, number] = [255, 128, 0];
// rgb = [255, 128]; // エラー
// rgb = [255, 128, 0, 1]; // エラー
TypeScriptRGB のように「3つで1セット」が決まっているデータには、タプルの型固定がとてもよくハマります。
各位置の型も固定される
順番を入れ替えるとエラーになる
let user: [string, number];
user = ["Taro", 20]; // OK
// user = [20, "Taro"]; // エラー:順番が違う
TypeScriptタプルは「1番目は string、2番目は number」という位置ごとの型まで固定します。
配列のように「全部 number」「全部 string」ではなく、「ここはこれ」という“位置付きの型”です。
アクセスしたときの型も位置で変わる
let user: [string, number] = ["Taro", 20];
const name = user[0]; // string
const age = user[1]; // number
// const x = user[2]; // エラー:そんな位置は存在しない
TypeScript普通の配列なら user[0] も user[1] も同じ型ですが、
タプルは「位置ごとに型が違う」ので、インデックスアクセスしたときの型も変わります。
これが「型が固定されている」ことの実感しやすいポイントです。
タプルの型固定がもたらす型安全性
間違ったデータ構造をコンパイル時に弾ける
固定長タプルにしておくと、「うっかり仕様と違う形のデータを作ってしまう」ことをコンパイル時に防げます。
type Range = [number, number];
function createRange(from: number, to: number): Range {
return [from, to]; // OK
// return [from]; // エラー
// return [from, to, 0]; // エラー
}
TypeScript「Range は必ず2つの number から成る」という仕様を、型として固定しているので、
将来誰かが間違った戻り値を書いても、その場でエラーになります。
データの一貫性を保ちやすくなる
固定長タプルは、「この構造はこういう形であるべき」という一貫性を保つのに向いています。
type UserRow = [number, string, boolean];
const users: UserRow[] = [
[1, "Taro", true],
[2, "Hanako", false],
// [3, true, "Jiro"], // エラー:型と順番が違う
];
TypeScriptここでは「id(number)、name(string)、isActive(boolean)」という順番と型が固定されています。
配列のまま書いているのに、実質的には“型付きの行データ”として扱えるわけです。
as const と組み合わせた「より強い型固定」
リテラル値まで固定される
as const を使うと、タプルの「型固定」がさらに強くなります。
const STATUS = ["success", "error"] as const;
// 型: readonly ["success", "error"]
TypeScriptここでは、
- 要素数は2つ
- 1番目は “success”
- 2番目は “error”
- 変更不可(readonly)
という、かなりガチガチに固定されたタプルになります。
「この並びそのものが仕様だ」というときには、as const とタプルの組み合わせはとても強力です。
初心者がまず掴んでおきたい「タプルの型固定」の感覚
タプルの型固定は、まとめるとこういう感覚です。
- 「要素数が決まっている配列」を作れる
- 「位置ごとに型が決まっている配列」を作れる
- 「その形から外れたらコンパイル時に即アウト」にできる
だからこそ、
- 2つや3つの値で1セットの意味を持つデータ
- 行データ([id, name, isActive] のようなもの)
- 「この形からズレてほしくない」構造
に対してタプルを使うと、「仕様そのものを型にしている」感覚が手に入ります。
「この2つ(3つ)は、順番と数が決まった1セットだな」と感じたら、
一度 [型1, 型2, 型3] というタプルで書いてみる。
そこから、「型を固定することの気持ちよさ」が、かなりはっきり見えてくるはずです。
