typescript - Ako získať návratový typ pre konkrétne parametre generickej funkcie?


Rád by som vytvoril pomocný typ, ktorý berie podpis generickej funkcie a jej argumenty. Mal by výsledkom byť typ návratovej hodnoty podpisu, akoby bol vykonaný s poskytnutými argumentmi.

Skúsil som toto:

type GetReturnType<T extends (...args: any) => any, B> = T extends (...args: any) => infer R ? R : never;

Ale všetky generiká nakoniec skončia ako unknown alebo never.

Niektoré príkladové funkcie, ktoré by som mohol chcieť odovzdať:

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");
    }
}

A ako by som chcel, aby sa používalo GetReturnType:

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"

Odkaz na ihrisko

TypeScript už má zavedený systém na odvodenie generických typov funkcií. Napríklad myFn3("some string") odvodí prvý generický argument ako string a následne vrátená hodnota bude "yes". Chcel by som využiť tento systém pri získavaní návratového typu. Iné otázky na SO sa pýtajú, ako to urobiť, keď sú generiká známe, ale ja by som chcel vedieť, ako to urobiť, keď sú generiká odvodené.

Odpoveď č. 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";
// }]

Myslím, že toto je najbližšie, ako sa dá dostať. Bolo by lepšie, keby sme mohli odovzdať to ako parameter, ale podľa mojich vedomostí to nie je možné.

Odpoveď č. 2

Tá istá otázka, prečo môžem vrátiť extra hodnotu

type RX = { id: number; name: string };
type GetProduct = (name: string) => RX;

const getProduct: GetProduct = (name) => ({ id: 123, name, city: "" });

ako mesto tu