何?関数型のオーバーロードを動的に生成できますか?

オーバーロードとは、関数が異なるパラメーターと戻り値を持つことができること、つまり、異なる関数シグネチャを持つことができることを意味します。

tsは関数のオーバーロードをサポートしており、同じ関数に対して複数の異なるタイプを定義できます。

オーバーロードを記述する方法は3つあります(ほとんどの人はおそらく1つしか持っていません)。

declare function func(name: string): string;
declare function func(name: number): number;
复制代码

これは、誰もがより一般的に使用します。オーバーロードの目的を達成するために、同じ名前の2つの関数を宣言します。

関数はインターフェースとして宣言でき、同様に、関数のオーバーロードはインターフェースとして宣言できます。

関数型は交差型を取ることができます。つまり、複数の型を使用できます。実際、関数のオーバーロードも意味します。

オーバーロードは非常に便利な機能ですが、オーバーロードが多すぎると書き込むのが非常に面倒な場合があります。

たとえば、tsによって提供されるlib.dom.tsには、次のような型の定義があります。

各パラメーターは異なる戻り値に対応しているため、非常に過負荷になっています。

このように書くのは面倒ですが、型プログラミングを使って動的に生成できますか?

オーバーロード、宣言、インターフェイスを記述する3つの方法を考えてみてください。ただし、&はOKです。共用体型を渡して、交差型を返すことはできますか?

例えば:

それは間違いなく可能であることが示唆されています。実装を見てみましょう。

ユニオンインターチェンジ

関数パラメーターには、共変性の性質があります。つまり、型が縮小されます。たとえば、パラメーターにA、B、Cを同時に渡すことができる場合、パラメーターの型を定義するにはどうすればよいですか。

A、B、Cのパラメータを受け取ることができるように、A、B、Cの交差、つまりA&B&Cの交差タイプである必要があります。

この特性を利用して、共同交差点を実現できます。

type UnionToIntersection<U> = 
    (U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown
        ? R
        : never
复制代码

テストがあります:

ここでの型パラメーターUは、入力共用体型であり、U拡張Uを追加すると、分散条件型の特性がトリガーされます。

分散条件タイプとは何ですか?

型パラメーターが共用体型であり、型パラメーターが条件型の左側で直接参照される場合、TypeScriptは型操作のために各要素を個別に渡し、最後にそれを共用体型にマージします。この構文は分散条件付きと呼ばれます。タイプ。

たとえば、次のような共用体タイプ:

type Union = 'a' | 'b' | 'c';
复制代码

aを大文字にしたい場合は、次のように記述できます。

type UppercaseA<Item extends string> = 
    Item extends 'a' ?  Uppercase<Item> : Item;
复制代码

この高レベルのタイプのユニオンジャンクションに戻ります。

UextendsUまたはUextendsanyを追加すると、分散条件型の特性をトリガーできるため、共用体型は各型に分割され、計算のために個別に渡され、最後に結果が共用体型にマージされます。

然后再把它放到函数参数的位置,构造一个函数类型,通过模式匹配的方式提取参数的类型到 infer 声明的局部变量 R 里返回。

这样的结果就是交叉类型。

原因上面说过了,函数参数有逆变的性质,传入联合类型会返回交叉类型。

实现了联合转交叉之后,函数重载也就可以写出来了:

比如三个重载的返回值分别是 Aaa、Bbb、Ccc:

我们想基于这个生成重载的类型定义,传入联合类型返回重载的函数:

就可以这样写:

type UnionToOverloadFunction<T extends keyof ReturnValueMap> = 
    UnionToIntersection<
        T extends any ? (type: T) => ReturnValueMap[T] : never
    >;
复制代码

类型参数 T 是 ReturnValueMap 里的 key,约束为 keyof ReturnValueMap。

通过 T extends any 触发联合类型在分布式条件类型中的分发特性,让 'aaa' 'bbb' 'ccc' 分别传入做计算,返回构造出的函数类型的联合。

我们先单独测试下这部分:

可以看到返回的是构造出的函数类型的联合类型。

然后就用上面的 UnionToIntersection 转交叉就可以了:

这样就实现了重载函数的动态生成:

对比下最开始那种写法:

是不是清爽多了!而且还可以写一些动态逻辑。

总结

ts 函数重载一共有三种写法: declare function、interface、交叉类型 &。

当重载比较多的时候,直接列出来还是比较麻烦的,这时候可以用类型编程来动态生成函数重载。

我们实现了联合转交叉,利用了函数参数的逆变性质,也就是当参数可能是多个类型时,会返回它们的交叉类型。

然后又利用分布式条件类型的性质,当传入联合类型时,会把类型单独传入做计算,最后把结果合并成联合类型。

利用这个实现了传入联合类型返回构造出的函数的联合类型,然后再结合联合转交叉就实现了函数重载的动态生成。

当你写重载写的太多的时候,不妨试一下用类型编程的方式动态生成吧!

おすすめ

転載: juejin.im/post/7085311864972214302