typescript - Inferir nueva función genérica a partir de una función genérica dada
Me gustaría envolver una función genérica dada (que no está bajo mi control) con mi propia función genérica.
p. ej.
type givenFunction= <T, V>(a: string, b: V) => Promise<T>;
// This is what I want, though I'd like to infer all of the types from `givenFunction`
type myFunction = <T, V>(b: V) => Promise<T>
Además, me gustaría reutilizar la mayoría de las definiciones de tipo de las funciones dadas (usando Parameters y ReturnType). Ya funciona en cierta medida, solo que ya no es genérico.
Aquí está el ejemplo del mundo real de lo que estoy tratando de hacer: TypeScript Playground
Respuesta #1
No puedes hacer esto puramente a nivel de tipo. Si estás de acuerdo con algunos efectos en tiempo de ejecución, puedes crear una función de orden superior que convierta una función genérica en otra. Por ejemplo:
function passInitialString<A extends any[], R>(t: string, f: (t: string, ...r: A) => R) {
return (...r: A) => f(t, ...r);
}
Esta función tomará cualquier función f cuyo primer argumento sea una cadena, y producirá otra función que no necesitará ese argumento. Puede que no parezca que suceda algo especial aquí, pero si f resulta ser genérica, entonces también lo será la función devuelta.
Usemos la función request de graphql-request en tu enlace de playground como ejemplo:
import { request as gqlRequest } from 'graphql-request';
declare const endpoint: string;
const request = passInitialString(endpoint, gqlRequest);
/*
const request: <T = any, V = Variables>(
document: RequestDocument,
variables?: V | undefined,
requestHeaders?: HeadersInit | undefined
) => Promise<T>
*/
El tipo request es genérico y tiene exactamente el tipo que deseas.
Si no quieres ningún efecto en tiempo de ejecución, no hay mucho que puedas hacer excepto escribir manualmente el tipo genérico deseado.
TypeScript no tiene soporte directo para tipos de orden superior del tipo solicitado en microsoft/TypeScript#1213, ni tampoco tiene valores genéricos del tipo solicitado en microsoft/TypeScript#17574, por lo que no hay manera de expresar el tipo de manipulación de tipos que estás realizando en el sistema de tipos.
Escribir los tipos manualmente es molesto, y no se actualiza automáticamente con el tipo de función original, y es posible que necesites declarar muchos otros tipos:
export type Variables = { [key: string]: any }
export type RequestDocument = string | DocumentNode
type Request = <T = any, V = Variables>(
document: RequestDocument,
variables?: V | undefined,
requestHeaders?: HeadersInit | undefined
) => Promise<T>
Así que con suerte estás de acuerdo con una solución como passInitialString().
Enlace de Playground al código
