mosya
mosya Business はこちら

mosya<TC> - 関数の引数の型を取得するMyParametersを作ろうの解説

この記事はmosya<TC>の問題の一つであるMyParameters型の解説になります。

問題

関数の引数の型をタプルで返す型を実装します。

例えば以下のようなコードを満たすように実装しましょう。

const foo = (
  arg1: string,
  arg2: number
): void => {};

type FunctionParamsType = MyParameters<
  typeof foo
>; // [arg1: string, arg2: number]

前提知識

この問題を解くにあたって型についての以下の知識を理解しておく必要があります。

  1. ジェネリクスを理解する
  2. Conditional Typesを理解する
  3. inferを理解する

まず、<T>というのは、ジェネリクスと呼ばれる機能です。ジェネリクスは、型をパラメータとして受け取ることができる機能です。

この受け取った値を使って、新しい型を生成することができます。

受け取った型を活用して、新しい型を生成することができるので、型の再利用性が高くなります。

例えば、以下のような型が考えられます

type Foo<T> = {
  bar: T;
};

この型は、Tという型を受け取り、barというプロパティにTを代入する型です。

この型を使うと、以下のように型を指定することができます。

type FooString = Foo<string>; // { bar: string }
type FooNumber = Foo<number>; // { bar: number }

このようにジェネリクスは型を引数として受け取って、新しい型を生成することができます。

型の制約

Textendsをつけることで制約をつけることができます。

例えば、T extends stringとすると、Tstring型かstring型を継承した型に制約されます。

Conditional Typesを理解する

Conditional Typesは、条件によって型を変更することができる機能です。

例えば、以下のような型が考えられます。

type Foo<T> = T extends string
  ? string
  : number;

この型は、Tstring型を継承している場合はstring型、そうでない場合はnumber型になります。

このように、Conditional Typesは条件によって型を変更することができます。

never型と組み合わせる

Conditional Typesは、never型と組み合わせることで、型の絞り込みを行うことができます。

例えば、以下のような型が考えられます。

type NonNullable<T> = T extends
  | null
  | undefined
  ? never
  : T;

この型は、Tnull型か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[]型が当てはまるので、Rstring型に推論され、Rを返すのでstring型が返されます。
このように推論される型を取得するのにinferは役立ちます。

解答例

以上の知識を踏まえて、解答例を見ていきましょう。

まず、MyParameters型を実装するにあたって、以下のような型を考えることができます。

type MyParameters<
  T extends (...args: any) => void
> = T extends (...args: infer R) => any
  ? R
  : never;

この型は、Tが関数の場合は、関数の引数の型を返します。
...argsを使うことで、関数の可変長引数を配列として受け取ることができます。

またConditional Typesinferを組み合わせることで、可変長引数の型を推論して取得することができます。

Authored by

筆者の写真

Godai@steelydylan

Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。

ReactやTypeScriptなどの周辺技術が学べる
オンライン学習サービスを作りました!

詳しくはこちら
mosya

mosyaはオンラインでHTML,CSS,JavaScriptを基本から学習できるサービスです。現役エンジニアが作成した豊富なカリキュラムに沿って学習を進めましょう。

© 2023 - mosya. All rights reserved.