こんにちは!TypeScriptの世界へようこそ。チーフアーキテクトの私です。
TypeScriptを触りはじめると、「string」「number」「boolean」といった基本の型から始まり、複数の型を順番に並べた「タプル型」という便利なものに出会いますよね。「配列と何が違うの?」「順番と型がカチッと決まっていて気持ちいい!」なんて感動したのも束の間、実務のコードを書いていると、こんな壁にぶつからお休みですか?
- 「既存のタプル型の先頭に、新しい要素をスッと差し込みたいんだけど、どう型付けすればいいの……?」
- 「APIから返ってくる複数の配列を合体させたいのに、型が `any[]` に落ちてしまって絶望した……」
大丈夫です、安心してついてきてください。今回は、そんなモヤモヤを鮮やかに吹き飛ばしてくれる、TypeScriptのちょっとカッコいい秘密兵器「Variadic Tuple Types(可変長タプル型)」について、おしゃべりするような気持ちで紐解いていきましょう。
—
そもそも「タプル型」ってどんなお弁当箱?
可変長タプル型の話をする前に、まずは基本の「タプル型」を復習しておきましょう。
配列(Array)が「同じ種類のおかずが何個入ってもいいバイキング形式のお皿」だとすると、タプル型(Tuple)は「仕切りがカチッと決まったお弁当箱」です。
// 1番目は文字列(名前)、2番目は数値(年齢)と決まっているタプル型
let user: [string, number] = [“さくら”, 28];
「お、いいね!」と思って使っているうちに、現場ではこんな要望が出てきます。
「このお弁当箱の先頭に、新しく『ID(数値)』の仕切りを1つ追加したい!」さあ、どうしましょう?
従来のTypeScriptだと、このお弁当箱の構造を改造するのはなかなか面倒でした。そこで登場するのが、今回の主役である可変長タプル型です。
—
可変長タプル型(Variadic Tuple Types)ってなんだろう?
名前を聞くと「うっ、難しそう……」とブラウザを閉じたくなるかもしれませんが、安心してください。やっていることはとってもシンプルです。
JavaScriptでおなじみのスプレッド構文(`…`)ってありますよね?あれを、「型」の世界でもやっちゃおうぜ!という機能です。
言葉で説明するより、コードを見たほうが早いです。お買い物のレシートを例に見てみましょう。
例1:レシートの品目を合体させる
例えば、「果物のリスト」と「お肉のリスト」という2つのタプル型(お弁当箱)があるとします。
type Fruits = [“りんご”, “みかん”];
type Meats = [“牛肉”, “豚肉”];
// この2つを合体させて、「お買い物カゴ」の型を作りたい!
type Basket = […Fruits, …Meats];
// 結果:[“りんご”, “みかん”, “牛肉”, “豚肉”] というタプル型になる!
すごい!`…`(スプレッド演算子)を型の定義の中で使うことで、お弁当箱と お弁当箱をパズルのように合体させることができちゃいました。これが可変長タプル型の基本のキです。
—
例2:先頭に要素をピタッと挿入する(実務でめちゃくちゃ使うテクニック)
Web制作やアプリケーション開発をしていると、「既存の関数の引数リストの先頭に、共通の引数(例えば `userId` など)を1つ追加した新しい関数型を作りたい」という場面に直面します。
そんな時こそ、可変長タプル型の出番です。
// もともとのイベント引数の型
type EventArguments = [string, boolean];
// 先頭に「数値のID」を1つ追加した、新しいタプル型を作りたい!
type ExtendedArguments = [number, …EventArguments];
// 出来上がった型の中身はこうなります:
// [number, string, boolean]
これ、すごくないですか?元の型を一切汚さずに、スプレッド構文を使って「先頭にポンッと要素を挟み込む」ことが型安全にできてしまうんです。実務で関数デコレータや高階関数を書くとき、このテクニックを知っているとコードが美しすぎて思わずコーヒーを淹れたくなります。
—
ジェネリクスと組み合わせると、本当の魔法になる
可変長タプル型の真骨頂は、「どんな長さのタプルが来るか分からない(ジェネリクス)」状況と組み合わせたときです。
「受け取った配列の先頭に、必ず `true`(フラグ)をくっつけて返す関数」を作ってみましょう。
// ジェネリクス(T)を使って、どんなタプル型が来ても受け止められるようにする
function addFlagToBeginning
実際の正しい書き方はこちらです。
// 引数にスプレッド型 T を受け取り、先頭に boolean を追加した新しいタプルを返す関数
function prependBoolean
return [true, …args];
}
// さあ、使ってみましょう!
const result = prependBoolean(“こんにちは”, 42);
// result の型はどうなる?
// 答え:[boolean, string, number]
// めちゃくちゃ型安全かつ、推論が完璧です!
`…args: T` でどんな長さの引数も受け取り、戻り値の型で `[boolean, …T]` と指定することで、「元の引数の前boisに必ず boolean がくっついた型」をTypeScriptが自動で計算してくれます。
初心者の方が最初につまずきやすいのは、「`T extends unknown[]` って何?」という部分ですが、これは「Tは配列(またはタプル)の形をしていてね」というTypeScriptへのやさしいお願い(制約)だと思ってください。
—
現場のエンジニアからの温かいアドバイス
ここまで読んでくれてありがとうございます。
可変長タプル型は、日々のコーディングで毎日使うような派手な機能ではありません。しかし、「既存の型をベースに、柔軟に形を変形させたい」という、少し一歩進んだレイヤーのコードを書くときには、なくてはならない強力な相棒になります。
最初は `[…T, string]` なんて見慣れない記号の羅列にクラクラするかもしれませんが、
「あ、型のお弁当箱をスプレッド構文でガチャガチャ組み替えて遊んでるんだな」
と、気楽なイメージを持って触ってみてください。
エラーが出ても大丈夫。TypeScriptの编译器(コンパイラ)は、あなたが正しい型にたどり着くまで、いつでも優しく赤線でヒントを教えてくれますからね。
それでは、快適なTypeScriptライフを!次の現場でも一緒に楽しくコードを書いていきましょう。

コメント