お題
Parameters<T>
を使用せずに、関数型から引数の型を取得し、配列を構想する形MyParameters
を実装する。
やりたいこと
const foo = (arg1: string, arg2: number): void => {}
type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]
解答
type MyParameters<T extends (...args:any[]) => any> =
T extends (...args: infer Arg) => any
? Arg
: never;
解説
処理の流れ
-
<T extends (...args:any[]) => any>
T
が関数型であることを制約する。 -
T extends (...args: infer Arg) => any
infer
を使って、引数の型を推論する。
Argの中身について
Arg
が推論される値は、引数リスト全体である。
type ExampleFunction = (x: number, y: string) => boolean;
type Result = MyParameters<ExampleFunction>;
引数部分の(x: number, y: string)
が、配列(タプル)型[number, string]
としてArg
に推論される。
関数の型を宣言するには?
関数の型を宣言するとは...
関数の実装を示さず、関数のインターフェースを定義すること。
関数の型宣言をする構文は2つある。
1. アロー関数構文
type 型の名前 = (引数名: 引数の型) => 戻り値の型;
type fn1 = (str: string) => string;
// string型を受け取り、string型を返す関数の型宣言
2. メソッド構文
type 型の名前 = {
(引数名: 引数の型): 戻り値の型
};
type fn2 = {
(str: string): string;
};
残余引数/可変長引数(...)とは...
引数の数が決まっていない関数を作ることができ、引数の個数が決まっていない引数のことを残余引数と呼ぶ。
残余引数の書き方
引数の前に、...
を書く。
function func(...params) {
// ...
};
残余引数のルール
- 受け取った引数は配列になる
function func(...params) {
console.log(params)
};
func(1, 2, 3); // => [1, 2, 3]
- 型注釈するには、配列の型を書く
// 残余引数がnumber型の場合
function func(...params: number[]) {
// ...
}
残余引数のルール
- 残余引数を複数持たせることはできない
// 構文エラーが出る例
function func(...params1, ...params2) {};
// A rest parameter must be last in a parameter list.
- 残余引数は必ず最後の引数でなければならない
// 構文エラーが出る例
function func(...params, param1) {};
// A rest parameter must be last in a parameter list.
関数の型の宣言と残余引数を使うことで...
上記の解説から、(...args: any[]) => any
の意味がわかるようになる!
関数から関数の型を宣言するには...
typeof演算子を使用する。
function func(num: number): number {
return num + 1
};
type Increment = typeof func; // => (num: number) => number
inferとは...
参考記事
関数の型の宣言について
残余引数について
今回の問題