こんにちは!フロントエンドからバックエンドまで、TypeScriptの荒波を一緒に航海していく先輩エンジニアです。
今回は、TypeScriptの型システムの中でも、ひときわ美しく、そして強力な武器となる「Variadic Tuple Types(可変長タプル型)」を用いた引数の型変換とマッピングについてお話しします。
「複数の引数をまとめて受け取って、ゴニョゴニョと型を変形させたい……」
そんな現場の要求に直面したとき、ここをクリアできれば、あなたのTypeScriptスキルは一段上のステージに到達します。難しく聞こえるかもしれませんが、一歩ずつ噛み砕いて解説していくので、安心してついてきてくださいね!
—
1. そもそも「タプル型」と「可変長引数」って何だっけ?
まずは基本のおさらいからいきましょう。
普通の配列(`string[]`など)は、「何個入っているか分からないけれど、中身は全部文字列」というデータ構造ですよね。
これに対してタプル型(Tuple Types)は、「1番目は `string`、2番目は `number`、3番目は `boolean`」というように、順番と型が厳密に決まった固定長の配列のことです。
// 3つの要素の型と順番が固定されたタプル型
type UserRecord = [string, number, boolean];
const record: UserRecord = [“Alice”, 30, true]; // バッチリOK!
そして、TypeScript 4.0で導入された Variadic Tuple Types を使うと、このタプル型の中に「スプレッド演算子(`…`)」を使って、可変長の要素を組み込んだり、個々の要素を別の型に一網打尽でマッピング(変換)したりできるようになったのです。
—
2. 実践!引数の型を「一括変換」する関数を作ってみよう
例えば、開発の現場で「受け取ったすべての引数を、後からロギングするために『文字列化(`string`への変換)』または『関数にラップ』したい」という状況を想像してみてください。
従来のTypeScriptだと、オーバーロードを何行も書くか、`any`で型安全性を捨てるしかありませんでした。しかし、Variadic Tuple Typesを使えば、こんな風に書けます。
/
- タプル型の各要素を Promise に包み込む型マッピング
/
type Promisify
[K in keyof T]: Promise
};
// 【イメージ図解】
// 入力: [string, number]
// 変換: [Promise
これを実際の関数に組み込んでみましょう。ここからが本番です!
// 引数のタプル型を受け取り、すべての要素をPromiseで包んだタプルを返す関数
function promisifyArgs
// 実行時は単にそのまま返す(今回は型の挙動に注目!)
return args.map(arg => Promise.resolve(arg)) as unknown as Promisify
}
// — 使い方と型推論の魔法 —
// 実行してみましょう
const results = promisifyArgs(“hello”, 42, true);
// 【重要】results の型は、手動で書かなくても自動的にこう推論されます!
// const results: [Promise
すごくないですか? 引数に渡した型(`string`, `number`, `boolean`)をTypeScriptのコンパイラが自動で読み取り、マッピング用の型定義(`Promisify
—
3. もう一歩実践的:引数の値を「バリデータ関数」のペアに変換する
もう少し現場で役立ちそうな例を見てみましょう。
「受け取った値の配列」ではなく、「値を受け取って検証するバリデーター関数の配列」に引数の型を変換したいケースです。
// 1つの型を「その型を引数に取ってbooleanを返す関数」に変換する型
type Validator
// タプル全体の各要素を Validator に変換するマッピング型
type ValidatorTuple
[K in keyof T]: Validator
};
// 実際にバリデーターのリストを作るファクトリ関数
function createValidators
return {
// 渡された値たちが、それぞれのバリデーターを通るかチェックするメソッド
validate(…args: T): boolean {
return validators.every((validator, index) => validator(args[index]));
}
};
}
// — 使用例 —
const userValidator = createValidators(
(name: string) => name.length > 0, // T[0] = string
(age: number) => age >= 18 // T[1] = number
);
// 型安全にチェックが走る!
userValidator.validate(“Alice”, 20); // OK! 戻り値は boolean
// userValidator.validate(“Alice”, “twenty”); // ❌ コンパイルエラー!2番目はnumberであるべきです
このコードでは、`createValidators` に渡す引数の型(`ValidatorTuple
ここがポイントなのですが、TypeScriptは「引数の型から戻り値の型を作る」だけでなく、「マッピングされた型から、元の引数の型を逆算する」という高度な推論もやってのけます。これができると、ライブラリの設計などで圧倒的に美しい型安全を提供できるようになります。
—
4. 陥りがちな罠とエラー回避のコツ
この Variadic Tuple Types を使いこなす上で、初学者がよくハマる落とし穴がいくつかあります。ここで先回りしてクリアしておきましょう。
罠1: `extends any[]` の制約を忘れる
ジェネリクスでタプル型を扱うときは、必ず `T extends any[]` のように、配列・タプルであることをコンパイラに伝えてあげる必要があります。これを忘れると、`[K in keyof T]` というマッピング操作で「そんなインデックス操作はできないよ」と怒られてしまいます。
罠2: `as unknown as …` のキャストの多用
TypeScriptの型システムは非常に賢いですが、配列の `map` メソッドの戻り値の型と、自作した複雑なマッピング型(`Promisify
そのため、実行時のコードと型が完全に一致している確信がある場合は、一時的に `as unknown as Promisify
—
まとめ:ここをクリアすればTypeScriptは怖くない!
お疲れ様でした!今回は以下のポイントを一緒に見てきました。
1. Variadic Tuple Types を使えば、可変長引数のタプル型を自由自在に変形できる。
2. `{ [K in keyof T]: … }` というマッピング構文で、要素ごとの型変換が一括で行える。
3. 引数の型から戻り値の型、あるいはその逆の推論をコンパイラに賢く行わせることができる。
ここをマスターできれば、単なる「型付きJavaScript」の枠を超えて、「TypeScriptの型システムをプログラミングする」という本当の面白さにたどり着きます。
日々の開発で「あ、ここ、タプルで型をマッピングできそうだな」と思いついたら、ぜひ今回のコードを思い出してみてください。あなたのコードベースが、より堅牢で美しいものになるはずです。それでは、また次の冒険でお会いしましょう!