mosya<TC> - 関数の引数の型を取得するMyParametersを作ろうの解説
この記事はmosya<TC>の問題の一つであるMyParameters型の解説になります。
問題
関数の引数の型をタプルで返す型を実装します。
例えば以下のようなコードを満たすように実装しましょう。
const foo = (
arg1: string,
arg2: number
): void => {};
type FunctionParamsType = MyParameters<
typeof foo
>; // [arg1: string, arg2: number]
前提知識
この問題を解くにあたって型についての以下の知識を理解しておく必要があります。
- ジェネリクスを理解する
- Conditional Typesを理解する
- inferを理解する
まず、<T>というのは、ジェネリクスと呼ばれる機能です。ジェネリクスは、型をパラメータとして受け取ることができる機能です。
この受け取った値を使って、新しい型を生成することができます。
受け取った型を活用して、新しい型を生成することができるので、型の再利用性が高くなります。
例えば、以下のような型が考えられます
type Foo<T> = {
bar: T;
};
この型は、T
という型を受け取り、bar
というプロパティにT
を代入する型です。
この型を使うと、以下のように型を指定することができます。
type FooString = Foo<string>; // { bar: string }
type FooNumber = Foo<number>; // { bar: number }
このようにジェネリクスは型を引数として受け取って、新しい型を生成することができます。
型の制約
T
はextends
をつけることで制約をつけることができます。
例えば、T extends string
とすると、T
はstring
型かstring
型を継承した型に制約されます。
Conditional Typesを理解する
Conditional Typesは、条件によって型を変更することができる機能です。
例えば、以下のような型が考えられます。
type Foo<T> = T extends string
? string
: number;
この型は、T
がstring
型を継承している場合はstring
型、そうでない場合はnumber
型になります。
このように、Conditional Typesは条件によって型を変更することができます。
never型と組み合わせる
Conditional Typesは、never
型と組み合わせることで、型の絞り込みを行うことができます。
例えば、以下のような型が考えられます。
type NonNullable<T> = T extends
| null
| undefined
? never
: T;
この型は、T
がnull
型かundefined
型を継承している場合はnever
型、そうでない場合はT
型になります。
よって、例えば、以下のような型が定義されていた場合、undefind
が除外された型が生成されます。
type Foo = NonNullable<
string | undefined
>; // string
このように、Conditional Typesはnever
型と組み合わせることで、型の絞り込みを行うことができます。
inferを理解する
infer
は、型を推論することができる機能です。
例えば、以下のような型が考えられます。
type ArrayItem<T> =
T extends (infer R)[] ? R : never;
この型は、T
が配列の場合は、配列の中の型を返します。
以下のように使うことができます。
type Foo = ArrayItem<string[]>; // string
この場合、infer R
にはstring[]
型が当てはまるので、R
はstring
型に推論され、R
を返すのでstring
型が返されます。
このように推論される型を取得するのにinfer
は役立ちます。
解答例
以上の知識を踏まえて、解答例を見ていきましょう。
まず、MyParameters
型を実装するにあたって、以下のような型を考えることができます。
type MyParameters<
T extends (...args: any) => void
> = T extends (...args: infer R) => any
? R
: never;
この型は、T
が関数の場合は、関数の引数の型を返します。
...args
を使うことで、関数の可変長引数を配列として受け取ることができます。
またConditional Types
とinfer
を組み合わせることで、可変長引数の型を推論して取得することができます。
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。