🐥
[TypeScript]10個までのオーバーロードされた関数型から引数の型や返り値の型を共用体で取り出す方法
こちらの記事を参考にしています。
10個までのオーバーロードに対応した戻り値の型を取得
10個までのオーバーロードに対応した戻り値型を返却するコードを作成してみました。
type OverloadReturnType<T> = T extends
{
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
(...args: any): infer R,
}
? R : never
// 以下、使い方
const niceFunc: {
(arg: string): { [key: string]: string };
(arg: boolean): boolean;
(arg: number): string;
(arg: string): number;
} = (arg) => {
return arg as never //dummy
}
type Func = typeof niceFunc;
// number
type Ret = ReturnType<Func>;
// string | number | boolean | {[key: string]: string;}
type Ret2 = OverloadReturnType<Func>;
Ret2
はstring | number | boolean | {[key: string]: string;}
になっています
ちなみに同様方法で引数型を取り出そうとすると交差型で取得してしまうので、使いどころの無い状態になりました。引数まで本気でやろうとすると元記事のuhyoさんがおっしゃるとおり力業しかないようです。
10個までのオーバーロードに対応したパラメータ型を取得する
これが力業です。
type OverloadFunction1<T> = T extends
{
(...args: infer P1): infer R1,
}
? [P1, R1] : never
type OverloadFunction2<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
}
? [P1, R1] | [P2, R2] : never
type OverloadFunction3<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
}
? [P1, R1] | [P2, R2] | [P3, R3] : never
type OverloadFunction4<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] : never
type OverloadFunction5<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] : never
type OverloadFunction6<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
(...args: infer P6): infer R6,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] | [P6, R6] : never
type OverloadFunction7<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
(...args: infer P6): infer R6,
(...args: infer P7): infer R7,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] | [P6, R6] | [P7, R7] : never
type OverloadFunction8<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
(...args: infer P6): infer R6,
(...args: infer P7): infer R7,
(...args: infer P8): infer R8,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] | [P6, R6] | [P7, R7] | [P8, R8] : never
type OverloadFunction9<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
(...args: infer P6): infer R6,
(...args: infer P7): infer R7,
(...args: infer P8): infer R8,
(...args: infer P9): infer R9,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] | [P6, R6] | [P7, R7] | [P8, R8] | [P9, R9] : never
type OverloadFunction10<T> = T extends
{
(...args: infer P1): infer R1,
(...args: infer P2): infer R2,
(...args: infer P3): infer R3,
(...args: infer P4): infer R4,
(...args: infer P5): infer R5,
(...args: infer P6): infer R6,
(...args: infer P7): infer R7,
(...args: infer P8): infer R8,
(...args: infer P9): infer R9,
(...args: infer P10): infer R10,
}
? [P1, R1] | [P2, R2] | [P3, R3] | [P4, R4] | [P5, R5] | [P6, R6] | [P7, R7] | [P8, R8] | [P9, R9] | [P10, R10] : never
type OverloadFunction<T> =
any extends OverloadFunction10<T> ? OverloadFunction10<T> :
any extends OverloadFunction9<T> ? OverloadFunction9<T> :
any extends OverloadFunction8<T> ? OverloadFunction8<T> :
any extends OverloadFunction7<T> ? OverloadFunction7<T> :
any extends OverloadFunction6<T> ? OverloadFunction6<T> :
any extends OverloadFunction5<T> ? OverloadFunction5<T> :
any extends OverloadFunction4<T> ? OverloadFunction4<T> :
any extends OverloadFunction3<T> ? OverloadFunction3<T> :
any extends OverloadFunction2<T> ? OverloadFunction2<T> :
any extends OverloadFunction1<T> ? OverloadFunction1<T> :
never
type OverloadParameters<T> = OverloadFunction<T>[0]
const niceFunc: {
(arg: string): { [key: string]: string };
(arg: boolean): boolean;
(arg: number): string;
(arg: string): number;
} = (arg) => {
return arg as never //dummy
}
type Func = typeof niceFunc;
//[[arg: string], {[key: string]: string;}] | [[arg: boolean], boolean] | [[arg: number], string] | [[arg: string], number]
type FunctionType = OverloadFunction<Func>
//[arg: string]
type Params1 = Parameters<Func>
//[arg: string] | [arg: boolean] | [arg: number] | [arg: string]
type Params2 = OverloadParameters<Func>
ということで取り出しに成功しました。Params2
は[arg: string] | [arg: boolean] | [arg: number] | [arg: string]
という状態になっています。
OverloadFunction
の方はパラメータと戻り値の対応関係もそのまま含まれています。
まとめ
力業は思いつきでざっと実装してみただけなので、もっとエレガントに書く方法があるかもしれません。
Discussion