typescript - Como obter o tipo de retorno para parâmetros específicos de uma função genérica?
Eu gostaria de criar um tipo utilitário que recebe uma assinatura de uma função genérica e seus argumentos. Ele deve resultar no tipo de retorno da assinatura como se fosse executado com os argumentos fornecidos.
Eu tentei isto:
type GetReturnType<T extends (...args: any) => any, B> = T extends (...args: any) => infer R ? R : never;
Mas todos os genéricos acabam sendo unknown ou never.
Algumas funções de exemplo que eu poderia querer passar:
function myFn1<T>(x: T) {
return {
a: x,
}
}
function myFn2<T>(x: T) {
return [x];
}
function myFn3<T>(x: T) {
if (typeof x == "string") {
return "yes" as (T extends string ? "yes" : "no");
} else {
return "no" as (T extends string ? "yes" : "no");
}
}
E como eu gostaria que GetReturnType fosse usado:
type Return1 = GetReturnType<typeof myFn1, [x: number]>; // expected {a: number}
type Return2 = GetReturnType<typeof myFn2, [x: number]>; // expected number[]
type Return3A = GetReturnType<typeof myFn3, [x: number]>; // expected "no"
type Return3B = GetReturnType<typeof myFn3, [x: string]>; // expected "yes"
Link do playground
O TypeScript já possui um sistema para inferir os tipos genéricos de funções. Por exemplo, myFn3("some string") irá inferir o primeiro argumento genérico como sendo uma string e, por sua vez, o valor retornado será "yes". Eu gostaria de utilizar esse sistema ao tentar obter o tipo de retorno. Outras perguntas no SO perguntam como fazer isso quando os genéricos são conhecidos, mas eu gostaria de saber como fazer isso quando os genéricos são inferidos.
Resposta #1
const to = <A>(value: A) => ({ value } as const);
type ApplyTo<A> = ReturnType<typeof to<A>>;
const map = <A extends unknown[]>(value: readonly [...A]) => value.map(to) as {
[K in keyof A]: ApplyTo<A[K]>;
};
type t2 = ReturnType<typeof map<["a", "b", "c"]>>;
// type t2 = [{
// readonly value: "a";
// }, {
// readonly value: "b";
// }, {
// readonly value: "c";
// }]
Acho que isso é o mais próximo que se chega. Seria melhor se pudéssemos passar to como um parâmetro, mas pelo que sei, isso não é possível.
Resposta #2
A mesma pergunta, por que eu posso retornar valor extra
type RX = { id: number; name: string };
type GetProduct = (name: string) => RX;
const getProduct: GetProduct = (name) => ({ id: 123, name, city: "" });
como Cidade aqui
