TypeScript Tipo Obtener el Tipo de Retorno de Genéricos de Tipo de Función Restringida
Básicamente, estoy tratando de encontrar una manera de usar tipos de funciones como tipos genéricos para encontrar el tipo de retorno de la función con la restricción que elija. Sin embargo, no estoy seguro de si es posible porque no entiendo cómo funcionan los parámetros de función genéricos en cláusulas condicionales. Esto es lo que estoy intentando actualmente:
type FooFormatter = <S extends string>(input: S) => `foo-${S}`;
type StringFormatter = <S extends string>(input: S, ...args: never) => string;
type ComputeFormatter<Input extends string, T extends StringFormatter> =
T extends (input: Input, ...args: never) => `${infer $Value}`
? $Value
: never;
type foo = ComputeFormatter<"hey", FooFormatter>; // this is `foo-${string}` but I want "foo-hey"
Enlace al Playground de TypeScript
En ComputeFormatter estoy tratando de ver si de alguna manera puedo restringir el genérico en T sobrescribiendo el primer parámetro de la función al tipo Input. ¡Gracias por cualquier ayuda!
Respuesta #1
Respuesta breve, hay un PR fusionado para TS4.7 para esta función. De particular relevancia para tu pregunta...
type Box<T> = ReturnType<typeof makeBox<T>>; // { value: T }
Esto está muy cerca de una solución para #37181. ¿Nos permitirá hacer...?
return { value }; }; // Can we do it or something similar? Currently doesn't compile :( type MakeBox<T> = ReturnType<typeof makeBox<T>> // As it now allows us to do (no generics though) const stringMakeBox = makeBox<string>; type MakeBox = ReturnType<typeof stringMakeBox> // And even more relevant to support generics if we can now do: type MakeBox = ReturnType<typeof makeBox<string>>
Sí, de hecho puedes usar ese patrón para capturar un tipo de retorno genérico de una función genérica. Esto es algo que anteriormente no era posible. Actualizaré la descripción del PR para incluir un ejemplo.
Comenta aquí
No puedo encontrar nada sobre si esto funciona con alias de tipos para funciones, o solo funciona con funciones en tiempo de ejecución (inferidas con typeof), pero posiblemente puedas usar las implementaciones en tiempo de ejecución reales y usar typeof según sea necesario
Aquí esto funciona en la versión nocturna, ten en cuenta que todavía necesitarás una implementación en tiempo de ejecución, si realmente implementa algo o no depende de ti, podría ser alguna función simulada que no devuelve nada
type FooFormatter = <S extends string>(input: S) => `foo-${S}`;
const FooFormatterImplementation: FooFormatter = {} as any; //mock implementation
type StringFormatter = <S extends string>(input: S, ...args: never) => string;
type foo = ReturnType<typeof FooFormatterImplementation<"hey">>
// ^? `type foo = "foo-hey"`
Mis dos centavos y más (Más cosas de posdata)
Recomiendo encarecidamente investigar algunos de los tipos que tienen en type-fest, si aún no lo has hecho. Especialmente
Split- O en general todas sus
utilidades para cambiar mayúsculas y minúsculas,
Leyendo la biblioteca, parece que tienes un buen sentido de los tipos, y creo que en realidad podrías estar limitado por la versión de TS de Deno.
Hay un montón de soluciones alternativas, pero no estoy seguro de si realmente son aplicables en tu caso de uso.
- https://stackoverflow.com/a/50006640/17954209
- https://stackoverflow.com/a/62620115/17954209
Editar: Solución alternativa con fusión de declaraciones e interfaces
Esto no depende de TS4.7 ¡Hurra!
type FooFormatter = <S extends string>(input: S) => `foo-${S}`;
type BarFormatter = <S extends string>(input: S) => `bar-${S}`
export interface Formatters {
FooFormatter: FooFormatter,
BarFormatter: BarFormatter
}
// then anyone wanting to add a custom formatter, has to modify and reexport the interface,
// this is similiarly done in @react-mui, using module augmentation
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html
function takeInnerTest<T extends string, FmtKey extends keyof Formatters>(input: T, formatter: FmtKey)
{
type formattersDiscriminated = {
[K in keyof Formatters]: Formatters[K]
}[FmtKey]
const __mockFunction: formattersDiscriminated = ((...args: any[]) => undefined) as any
const __mockReturn = __mockFunction(input)
type String = ReturnType<typeof __mockFunction>
type ReturnValue = Extract<typeof __mockReturn, String>
return null! as ReturnValue
}
const foo3 = takeInnerTest("hey", "FooFormatter")
type foo3 = typeof foo3
// ^?
const foo4 = takeInnerTest("hey", "BarFormatter")
type foo4 = typeof foo4
// ^?
Campo de Juegos TS
