¿Qué? ¿Se puede generar dinámicamente la sobrecarga del tipo de función?

La sobrecarga significa que una función puede tener diferentes parámetros y valores de retorno, es decir, tener diferentes firmas de función.

ts admite la sobrecarga de funciones, puede definir varios tipos diferentes para la misma función:

Hay tres formas de escribir sobrecarga (la mayoría de las personas probablemente solo tengan una):

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

Esto es más comúnmente utilizado por todos. Declare dos funciones con el mismo nombre para lograr el propósito de sobrecarga:

Las funciones se pueden declarar como interfaces y, de manera similar, las sobrecargas de funciones se pueden declarar como interfaces:

El tipo de función puede tomar el tipo de intersección, es decir, se pueden usar múltiples tipos, de hecho, también significa sobrecarga de funciones:

Aunque la sobrecarga es una característica muy útil, a veces es bastante problemático escribir si hay demasiadas sobrecargas.

Por ejemplo, existe una definición de tipo de este tipo en lib.dom.ts proporcionada por ts:

Debido a que cada parámetro corresponde a un valor de retorno diferente, está demasiado sobrecargado.

Es demasiado problemático escribir así, ¿puedes usar programación de tipos para generarlo dinámicamente?

Considere que las tres formas de escribir la sobrecarga, la declaración y la interfaz no son buenas, pero & está bien, ¿puedo pasar un tipo de unión y luego devuelve el tipo de intersección?

Por ejemplo:

Se ha sugerido que definitivamente es posible, echemos un vistazo a la implementación:

Intercambio de unión

Los parámetros de la función tienen la propiedad de contravarianza, es decir, el tipo se reduce.Por ejemplo, si los parámetros se pueden pasar A, B y C al mismo tiempo, ¿cómo definir el tipo de parámetro?

Debe ser la intersección de A, B y C, es decir, el tipo de intersección de su A, B y C, para que pueda recibir los parámetros de A, B y C.

Esta propiedad se puede aprovechar para lograr una intersección transversal conjunta.

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

tener una prueba:

El parámetro de tipo U aquí es el tipo de unión entrante, y agregar una U extiende U es activar las características del tipo condicional distribuido.

¿Qué es un tipo de condición distribuida?

Cuando el parámetro de tipo es un tipo de unión y se hace referencia directa al parámetro de tipo en el lado izquierdo del tipo condicional, TypeScript pasará cada elemento por separado para la operación de tipo y finalmente lo fusionará en un tipo de unión. Esta sintaxis se denomina condicional distribuida tipo.

Por ejemplo, un tipo de unión como este:

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

Si queremos poner la a en mayúscula, podemos escribir:

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

Volviendo a este tipo de cruce de unión de alto nivel:

Agregar un U extends U o U extends any puede desencadenar las características del tipo condicional distribuido, de modo que el tipo de unión se divide en cada tipo y se pasa por separado para el cálculo, y finalmente el resultado se fusiona en un tipo de unión.

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

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

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

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

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

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

Supongo que te gusta

Origin juejin.im/post/7085311864972214302
Recomendado
Clasificación