タプルとは何か(「位置に意味がある配列」)
タプルは、ざっくり言うと「要素の数と順番と型が決まっている配列」です。
普通の配列は「同じ型の値がズラッと並ぶもの」ですが、タプルは「1番目はこれ、2番目はこれ…と、位置ごとに型と意味が決まっているもの」です。
let user: [string, number] = ["Taro", 20];
TypeScriptこの user は、「1番目が名前(string)、2番目が年齢(number)」という“2つセットのデータ”を表しています。
配列っぽく見えるけれど、「長さ」と「各位置の型」が型レベルで固定されている——これがタプルの本質です。
普通の配列との違いをはっきりさせる
配列:中身は同じ型、長さはバラバラ
let scores: number[] = [80, 90, 100];
scores[0]; // number
scores[1]; // number
scores[2]; // number
TypeScriptnumber[] は「number がいくつ並んでいてもいい」という型です。
長さは自由で、どの位置を取っても型は number です。
タプル:位置ごとに型が違う、長さも決まっている
let user: [string, number] = ["Taro", 20];
const name = user[0]; // string
const age = user[1]; // number
// const x = user[2]; // エラー:そんな位置はない
TypeScriptここでは「要素数は2つ」「1番目は string」「2番目は number」と決まっています。
3つ目を読もうとするとコンパイルエラーになりますし、順番を入れ替えることもできません。
// user = [20, "Taro"]; // エラー:型の順番が違う
TypeScript「順番に意味があるペア・トリプル」を表現したいときに、タプルはとても相性がいいです。
タプルの基本的な書き方と使い方
2要素タプル(ペア)
let point: [number, number] = [10, 20];
const x = point[0]; // number
const y = point[1]; // number
TypeScript「x座標とy座標」「幅と高さ」「開始時間と終了時間」など、2つで1セットのものを表すのに向いています。
3要素以上のタプル
let log: [string, number, boolean] = ["login", 200, true];
TypeScript「イベント名」「ステータスコード」「成功フラグ」のように、3つ以上の情報を1セットにすることもできます。
ただし、要素が増えるほど「どの位置が何の意味か」が分かりにくくなるので、
3〜4個を超えてくるならオブジェクトの方が読みやすいことも多いです。
タプルが役に立つ典型的な場面
関数から「複数の値」を返したいとき
JavaScriptでは、関数から1つの値しか返せませんが、配列やオブジェクトに包めば複数返せます。
タプルを使うと、「何を返しているか」を型でカッチリ表現できます。
function splitName(fullName: string): [string, string] {
const [first, last] = fullName.split(" ");
return [first, last];
}
const [first, last] = splitName("Taro Yamada");
// first: string, last: string
TypeScriptここで [string, string] としておくことで、
「戻り値は必ず2つの string で、1つ目と2つ目に意味がある」ということが型に刻まれます。
タプルの配列(「行」の集まり)として使う
type UserRow = [number, string];
const users: UserRow[] = [
[1, "Taro"],
[2, "Hanako"]
];
TypeScript「id と name のペアがたくさん並んでいる」という構造を、
「UserRow の配列」として表現できます。
このとき、users[0][0] は必ず number、users[0][1] は必ず string です。
タプルと配列の「型推論」の違い
普通に書くと配列として推論される
const user = ["Taro", 20];
// 型: (string | number)[]
TypeScript何も指定しないと、「string と number が混ざった配列」として推論されます。
この場合、user[0] も user[1] も string | number になり、位置ごとの意味は失われます。
タプルとして扱いたいなら、型注釈か as const
const user: [string, number] = ["Taro", 20];
TypeScriptまたは、
const user = ["Taro", 20] as const;
// 型: readonly ["Taro", 20]
TypeScriptと書くと、「1番目は string、2番目は number」というタプルとして扱われます。as const の場合は readonly も付くので、「順番も中身も変えない前提のタプル」になります。
タプルを使うかオブジェクトを使うかの判断
タプルが向いているケース
位置と意味がほぼセットで頭に入るような、シンプルなペア・トリプルはタプルが向いています。
座標([x, y])
サイズ([width, height])
範囲([start, end])
type Range = [number, number];
const r: Range = [0, 10];
TypeScriptこのくらいなら、「1番目が start、2番目が end」とすぐに分かります。
オブジェクトの方が向いているケース
一方で、要素が増えたり、意味が複雑になってきたら、オブジェクトの方が読みやすいです。
// タプルだと意味が分かりにくい
type UserTuple = [number, string, boolean];
// オブジェクトの方が明らかに読みやすい
type User = {
id: number;
name: string;
isActive: boolean;
};
TypeScript「コードを読む人が、位置の意味を覚えていないと辛い」ようなデータは、
タプルではなくオブジェクトにしてあげた方が親切です。
初心者がまず掴んでおきたいタプルの感覚
タプルは、ただの「型が混ざった配列」ではなく、
「要素数と順番と型が決まっている、小さなレコード」だと捉えるとしっくりきます。
配列:同じ型の値がズラッと並ぶ
タプル:位置ごとに意味が決まった、固定長のセット
「この2つ(3つ)は、順番に意味がある1セットだな」と感じる場面が出てきたら、
一度タプルで表現してみる。
そこから、「どこまでタプルでいくか」「どこからオブジェクトにするか」という感覚が、少しずつ自分の中で育っていきます。
