Quelle? La surcharge de type de fonction peut-elle être générée dynamiquement ?

La surcharge signifie qu'une fonction peut avoir des paramètres et des valeurs de retour différents, c'est-à-dire avoir des signatures de fonction différentes.

ts prend en charge la surcharge de fonctions, vous pouvez définir plusieurs types différents pour la même fonction :

Il existe trois façons d'écrire la surcharge (la plupart des gens n'en ont probablement qu'une) :

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

Ceci est plus couramment utilisé par tout le monde. Déclarez deux fonctions avec le même nom pour atteindre l'objectif de surcharge :

Les fonctions peuvent être déclarées en tant qu'interfaces, et de même, les surcharges de fonctions peuvent être déclarées en tant qu'interfaces :

Le type de fonction peut prendre le type d'intersection, c'est-à-dire que plusieurs types peuvent être utilisés, en fait, cela signifie également une surcharge de fonction :

Bien que la surcharge soit une fonctionnalité très utile, il est parfois assez difficile d'écrire s'il y a trop de surcharges.

Par exemple, il existe une telle définition de type dans lib.dom.ts fournie par ts :

Parce que chaque paramètre correspond à une valeur de retour différente, il est tellement surchargé.

C'est trop gênant pour écrire comme ça, pouvez-vous utiliser la programmation de type pour le générer dynamiquement ?

Considérez que les trois façons d'écrire la surcharge, déclarer et interface ne sont pas bonnes, mais & est OK, puis-je passer un type d'union, puis il renvoie le type d'intersection ?

Par example:

Il a été suggéré que c'est tout à fait possible, jetons un coup d'œil à la mise en œuvre :

Échange syndical

Les paramètres de fonction ont la propriété de contravariance, c'est-à-dire que le type est réduit. Par exemple, si les paramètres peuvent être transmis A, B et C en même temps, comment définir le type de paramètre ?

Ce doit être l'intersection de A, B et C, c'est-à-dire le type d'intersection de votre A & B & C, afin que vous puissiez recevoir les paramètres de A, B et C.

Cette propriété peut être exploitée pour réaliser une trans-intersection commune.

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

fais un test:

Le paramètre de type U ici est le type d'union entrant, et l'ajout d'un U étend U consiste à déclencher les caractéristiques du type conditionnel distribué.

Qu'est-ce qu'un type de condition distribué ?

Lorsque le paramètre de type est un type union et que le paramètre de type est directement référencé sur le côté gauche du type conditionnel, TypeScript transmettra chaque élément séparément pour l'opération de type, et le fusionnera finalement dans un type union.Cette syntaxe est appelée conditionnelle distribuée taper.

Par exemple, un type d'union comme celui-ci :

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

Si on veut mettre le a en majuscule, on peut écrire :

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

Revenons à ce type de jonction d'union de haut niveau :

L'ajout d'un U étend U ou U étend tout peut déclencher les caractéristiques du type conditionnel distribué, de sorte que le type union est divisé en chaque type et transmis séparément pour le calcul, et enfin le résultat est fusionné dans un type union.

然后再把它放到函数参数的位置,构造一个函数类型,通过模式匹配的方式提取参数的类型到 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、交叉类型 &。

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

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

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

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

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

Je suppose que tu aimes

Origine juejin.im/post/7085311864972214302
conseillé
Classement