TypeScript | 基礎文法:配列・タプル – タプルと配列の違い

TypeScript
スポンサーリンク

まずざっくりしたイメージの違い

同じ「[]」を使うのでややこしいんですが、役割はけっこう違います。

配列:
「同じ型の値が、いくつ並ぶか分からない入れ物」

タプル:
「要素の数・順番・型が決まっている、小さな“セット”」

このイメージを頭に置いたまま、具体的に見ていきます。


配列の特徴:同じ型がズラッと並ぶ

型は1種類、長さは自由

let scores: number[] = [80, 90, 100];

scores[0]; // number
scores[1]; // number
scores[2]; // number
TypeScript

number[] は「number が何個並んでいてもいい」という意味です。
要素数は 0 個でも 100 個でもよくて、どの位置を取っても型は number です。

scores.push(120); // OK
scores = [];      // これもOK(空配列)
TypeScript

配列は「同じ種類のものがたくさん並ぶ」ことに向いています。
ユーザー一覧、点数一覧、ID一覧…そういう「○○のリスト」はだいたい配列です。

型推論も「同じ型の配列」として働く

const names = ["Taro", "Hanako"];
// 型: string[]
TypeScript

要素が全部 string なら、「string の配列」として推論されます。
配列は「中身の型を1つにまとめる」方向に働きます。


タプルの特徴:位置ごとに型と意味が決まっている

要素数も順番も型も固定

let user: [string, number] = ["Taro", 20];

const name = user[0]; // string
const age = user[1];  // number
TypeScript

ここで決まっているのは、

1番目は string
2番目は number
要素数は必ず2つ

ということです。

// user = ["Taro"];        // エラー:足りない
// user = ["Taro", 20, 1]; // エラー:多い
// user = [20, "Taro"];    // エラー:順番が違う
TypeScript

配列が「同じ型がたくさん」なのに対して、
タプルは「位置ごとに型が違う、固定長のセット」です。

「位置に意味がある」データに向いている

let point: [number, number] = [10, 20]; // [x, y]
let size: [number, number] = [1920, 1080]; // [width, height]
TypeScript

「2つで1セット」「3つで1セット」のように、
順番と数に意味があるデータはタプルが得意です。


「長さ」と「位置」の扱いの違い

配列:長さは型に含まれない

let xs: number[] = [1, 2, 3];

xs = [1];        // OK
xs = [1, 2, 3, 4]; // OK
TypeScript

number[] という型は、「number が並んでいる」ということしか保証しません。
「何個あるか」は型の外側の話です。

タプル:長さも型の一部

let rgb: [number, number, number] = [255, 128, 0];

// rgb = [255, 128];      // エラー
// rgb = [255, 128, 0, 1]; // エラー
TypeScript

タプルは「3つで1セット」ということまで型に含まれます。
「長さが決まっている配列」が欲しいときは、タプル一択です。


「中身の型」の扱いの違い

配列:基本は「全部同じ型」

let ids: number[] = [1, 2, 3];
TypeScript

配列は「同じ型の値が並ぶ」ことを前提にしています。
もちろん (number | string)[] のようにユニオン型の配列も書けますが、
それでも「どの位置も number | string」という意味で、「位置ごとの差」はありません。

タプル:位置ごとに型が違う

let log: [string, number, boolean] = ["login", 200, true];

const event = log[0]; // string
const status = log[1]; // number
const success = log[2]; // boolean
TypeScript

タプルは「1番目はこれ」「2番目はこれ」「3番目はこれ」と、
位置ごとに型と意味が変わります。
ここが配列との一番大きな違いです。


型推論の違い(そのまま書くと配列になる)

何も指定しないと「混ざった配列」になる

const user = ["Taro", 20];
// 型: (string | number)[]
TypeScript

型注釈を書かないと、「string と number が混ざった配列」として扱われます。
この場合、user[0]user[1]string | number で、位置ごとの意味は失われます。

タプルとして扱いたいなら、型注釈か as const

const user1: [string, number] = ["Taro", 20];
TypeScript

または、

const user2 = ["Taro", 20] as const;
// 型: readonly ["Taro", 20]
TypeScript

と書くと、「1番目は string、2番目は number」というタプルとして扱われます。
「位置に意味を持たせたいなら、タプルとして宣言する」がポイントです。


どう使い分ければいいかの感覚

配列を選ぶとき

同じ型のデータがたくさん並ぶとき。
「ユーザー一覧」「ID一覧」「点数一覧」など、
「○○のリスト」と言いたくなるものは、まず配列です。

type User = { id: number; name: string };

const users: User[] = [
  { id: 1, name: "Taro" },
  { id: 2, name: "Hanako" }
];
TypeScript

タプルを選ぶとき

「2つ(3つ)で1セット」「順番に意味がある」と感じるとき。
座標、範囲、サイズ、関数の戻り値のペアなどはタプルが気持ちいいです。

type Range = [number, number];

function createRange(from: number, to: number): Range {
  return [from, to];
}

const [start, end] = createRange(0, 10);
TypeScript

「これはリストか?セットか?」
そう自分に問いかけてみると、配列とタプルのどちらがしっくりくるかが見えてきます。

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