こんにちは、かつコーチです。
前回はstring・number・booleanという基本の型注釈を解説しました。
今回は、複数の値をまとめて扱う「配列」の型の書き方と、配列に似ているけれど少し特殊な「タプル」という型を紹介します。
配列の型の書き方
基本の書き方:型名 + []
配列の型は、要素の型の後ろに[]を付けて表します。
let names: string[] = ["かつコーチ", "たなか", "すずき"];
let scores: number[] = [80, 95, 60];
let flags: boolean[] = [true, false, true];
string[]は「文字列だけが入る配列」、number[]は「数値だけが入る配列」という意味です。
ジェネリクス形式の書き方
配列の型には、もう1つArray<型名>という書き方もあります。
let names: Array<string> = ["かつコーチ", "たなか"];
let scores: Array<number> = [80, 95];
string[]とArray<string>は意味としては同じもので、どちらを使ってもかまいません。
現場ではstring[]のようなシンプルな書き方の方がよく使われる印象があるので、迷ったらこちらを基本にしておけば問題ありません。
型に合わない値を入れようとすると
let scores: number[] = [80, 95, 60];
scores.push(100); // OK:number型なので追加できる
scores.push("満点"); // エラー: Argument of type 'string' is not assignable to parameter of type 'number'.
pushで要素を追加するときも、型チェックはしっかり働きます。
配列の中に、うっかり型の違う値を紛れ込ませてしまう事故を防いでくれます。
複数の型を許容する配列
ユニオン型を組み合わせる
「文字列と数値、どちらも入る可能性がある配列」を扱いたい場合は、|(ユニオン型)を組み合わせます。
let mixedList: (string | number)[] = ["かつコーチ", 35, "たなか", 28];
(string | number)[]は「文字列または数値が入る配列」という意味です。
括弧を忘れてstring | number[]と書いてしまうと、「文字列、または数値の配列」という別の意味になってしまうので注意しましょう。
タプル型:要素数と順序が決まった配列
配列との違い
TypeScriptには、配列と似ているけれど少し特殊なタプルという型があります。
タプルは「要素数が決まっていて、それぞれの位置ごとに型も決まっている配列」です。
let userInfo: [string, number] = ["かつコーチ", 35];
[string, number]は「1番目は必ず文字列、2番目は必ず数値」という意味です。
普通の配列は「同じ型の値が何個でも入る」ものですが、タプルは「決まった数・決まった順番の値を1セットとして扱う」ためのものだとイメージすると分かりやすいです。
タプルの活用例
タプルは、意味の異なる値を1つのペアとして扱いたいときに便利です。
// [ユーザー名, 年齢] というペアの配列
const users: [string, number][] = [
["かつコーチ", 35],
["たなか", 28],
["すずき", 42],
];
for (const [name, age] of users) {
console.log(`${name}さんは${age}歳です`);
}
// かつコーチさんは35歳です
// たなかさんは28歳です
// すずきさんは42歳です
[string, number][]のように書くと、「[文字列, 数値]というタプルの配列」を表せます。
順序や個数が違うとエラーになる
タプルは、順序や個数が定義と異なるとエラーになります。
let userInfo: [string, number];
userInfo = [35, "かつコーチ"]; // エラー:順番が逆
userInfo = ["かつコーチ", 35, true]; // エラー:要素数が多い
userInfo = ["かつコーチ", 35]; // OK
「1番目は文字列、2番目は数値」という約束を破ると、その場でエラーとして教えてくれます。
かつコーチが実際につまずいたポイント:配列とタプルの使い分け
何でも配列で済ませようとして読みにくくなった話
私がタプルをまだ知らなかった頃、「名前と年齢のペア」のようなデータも、とりあえずstring[]やany[]のような普通の配列で済ませてしまっていました。
❌ Before:普通の配列で済ませてしまう
function createUserRow(data: any[]): string {
// data[0] が名前、data[1] が年齢のつもりだが…
return `${data[0]}さんは${data[1]}歳です`;
}
createUserRow(["かつコーチ", 35]); // 意図通り動く
createUserRow([35, "かつコーチ"]); // 順番を間違えても型エラーにならない
any[]にしてしまうと、配列の中身が何番目にどんな型で入っているかをTypeScriptがまったくチェックしてくれません。
引数の順番を間違えて渡しても、コンパイルの段階ではエラーにならず、実行してから「表示がおかしい」と気づくパターンを何度も経験しました。
✅ After:タプルで順序と型を固定する
function createUserRow(data: [string, number]): string {
return `${data[0]}さんは${data[1]}歳です`;
}
createUserRow(["かつコーチ", 35]); // OK
createUserRow([35, "かつコーチ"]); // エラー:1番目はstring型である必要がある
[string, number]とタプルで定義しておけば、「1番目は名前(文字列)、2番目は年齢(数値)」という約束がコードに固定され、順番を間違えた時点でエラーとして気づけます。
この経験から、私は「同じ型の値がいくつも並ぶだけなら配列」「意味の異なる値が決まった順番で組になるならタプル」と使い分けるようにしています。
迷ったときは、この基準に立ち返ると判断しやすいはずです。
まとめ
この記事のポイント
- 配列の型は
型名[](またはArray<型名>)で表す - 複数の型を許容する配列は
(型A | 型B)[]のようにユニオン型と組み合わせる - タプルは要素数と順序が固定された配列で、
[型A, 型B]のように書く - 意味の異なる値を1セットで扱いたいときは、配列よりタプルの方が安全にミスを防げる
any[]で済ませてしまうと、順序や型のチェックが効かなくなるので避ける
次に読むべき記事
配列とタプルの型が扱えるようになったら、次はより複雑なデータ構造である「オブジェクトの型を定義する方法」を見ていきましょう。
→ 次の記事:オブジェクトの型を定義する方法