残余引数/可変長引数(Rest parameter) は、関数に可変長の引数を受け取ることができる機能です。この機能を利用することで、関数に可変長の引数を受け取ることができます。
function sum(...args: number[]) {
return args.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3)); // 6
では、この時、sum
関数の引数の名前はどうなっているでしょうか?VSCodeで定義を書くにすると、 ...args
という名前になっています。わかりやすいですね。
では、下記のように、 number[]
ではなく [number, number, number]
という型を指定した場合はどうなるでしょうか?
function sum(...args: [number, number, number]) {
return args.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3)); // 6
引数の名前は args_1
, args_2
, args_3
という名前になっています。ちなみにVSCodeのinlay hintには引数名が表示されていません。なのでどちらかと言うと「無名の引数」という感じです。
今回はこの args_1
に名前をつけるお話です。
残余引数の要素に名前を付与する
では、下記のように [num1: number, num2: number, num3: number]
というような型を指定するとどうなるでしょうか?
function sum(...args: [num1: number, num2: number, num3: number]) {
return args.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3));
画像のように、記載した名前がそのまま引数の名前になります。
ラベル付きタプル
これはTypeScript 4.0で登場したラベル付きタプルという構文です。TypeScript 4.0というとVariadic Tuple Types
という、ジェネリクスに対する可変長の型と、末尾以外の箇所の可変長の型を指定する機能が目玉機能でしたね。
このラベル付きタプル(Labeled Tuple)は上記に記載した以上のものはなく、開発者の体験向上が目的のとなっています。[1]
使い所
EventEmitterのようなもので効力を発揮すると思います。下記のような実装ができます。正直実装は as
をめっちゃ指定しているのであまり良くないですが、JavaScriptの実装に型を指定する場合は良いかなと思います。
type Events = {
click: {
args: [target: string, mousePosition?: { x: number, y: number }],
result: { clicked: boolean },
},
type: {
args: [target: string, key: "Enter" | "Tab"],
result: { typed: boolean },
}
}
function on<T extends keyof Events>(event: T, ...args: Events[T]["args"]): Events[T]["result"] {
switch(event) {
case "click":
return click(...(args as Events["click"]["args"])) as Events["click"]["result"]
case "type":
return type(...(args as Events["type"]["args"])) as Events["type"]["result"]
default:
throw new Error("Invalid event")
}
}
on("click", "button", { x: 10, y: 20 })
on("type", "input", "Enter")
VSCodeで開くと画像のようにinlay hintで適切な引数名が表示されます。
ちなみにASTでは
NamedTupleMember
という要素名になっています。 ↩︎