TypeScriptでは関数の型定義のやり方がいくつかあり、よく理解できていなかったのでまとめてみます。
型定義の書き方
関数の型定義は2種類の書き方が存在します。
省略記法
省略記法では(引数の型) => 戻り値の型の形式で記述します。
アロー関数と同じような書き方です。
type Example1 = (param: string) => string;
const example1: Example1 = param => param;
example1は型Example1の型アノテーションをつけて、関数を定義しています。
型アノテーションによって関数の引数が推論され、引数のparamはstring型と解釈されます。
完全記法
完全記法では(引数の型): 戻り値の型という組を{}の中に記述します。
type Example2 = {
(param: string): string;
}
const example2: Example2 = param => param;
型定義のExample2とExample1は全く同じ意味になります。
関数のオーバーロード
完全記法では{}の中に複数の(引数の型): 戻り値の型を記述できます。
その場合はオーバーロードを意味します。
type Example3 = {
(): string;
(param: string): string;
(param: number): string;
}
const example3: Example3 = (param?: string | number) => `${param}`;
example3.tsに定義された型Example3を見ると戻り値はすべてstringです。
一方、第一引数は型はundefined,string,numberの3種類が定義されています。
この場合、第一引数の型は3種類のいずれかであると解釈されます。
すなわちparamsの型はundefined | string | numberになります。
example3.tsを省略記法で書くとexample4.tsのようになります。
type Example4 = (param?: string | number) => string
const example4: Example4 = (param?: string | number) => `${param}`;
ジェネリクスの使い方
省略記法
省略記法の場合、ジェネリクスは関数の引数の前に<>で囲んで定義します。
type Example5 = <T>(param: T) => T;
const example5: Example5 = param => param;
typeの変数名の右側にも書くことが可能です。
この場合は型アノテーションでジェネリクスの型を定義する必要があります。
type Example6<T> = (param: T) => T;
const example6: Example6<number> = (param) => param;
// 以下はエラー
// const example6: Example6 = (param) => param;
完全記法
完全記法の場合も省略記法と同様に関数の引数の前に<>で囲んでジェネリクスを定義します。
type Example7 = {
(): string;
<T>(param: T): string;
}
const example7: Example7 = (param?: number) => `${param}`;
typeの変数名の右側に書くことも可能です。
この場合は、複数の(引数の型): 戻り値の型に適用できます。
type Example8<T> = {
(): T;
(param: string): T;
(param: number): T;
}
const example8: Example8<string> = (param?: string | number) => `${param}`;