Website-Suche

Typescript Rückgabetyp einer generischen Funktion


Der neue ReturnType in TypeScript 2.8 ist ein wirklich nützliches Feature, das es Ihnen ermöglicht, den Rückgabetyp einer bestimmten Funktion zu extrahieren.

function foo(e: number): number {
    return e;
}

type fooReturn = ReturnType<typeof foo>; // number

Allerdings habe ich Schwierigkeiten, es im Kontext von generischen Funktionen zu verwenden.

function foo<T>(e: T): T {
    return e;
}

type fooReturn = ReturnType<typeof foo>; // type fooReturn = {}

type fooReturn = ReturnType<typeof foo<number>>; // syntax error

type fooReturn = ReturnType<(typeof foo)<number>>; // syntax error

Gibt es eine Möglichkeit, den Rückgabewerttyp zu extrahieren, den eine generische Funktion für bestimmte Typparameter hätte?

Antwort #1

Dies war zuvor in rein generischer Form unmöglich, wird aber in Typescript 4.7 möglich sein. Das Muster wird "Instanziierungsausdruck" genannt. Der relevante PR ist hier. Auszug aus der Beschreibung:

function makeBox<T>(value: T) {
  return { value };
};

const makeStringBox = makeBox<string>;  // (value: string) => { value: string }
const stringBox = makeStringBox('abc');  // { value: string }

const ErrorMap = Map<string, Error>;  // new () => Map<string, Error>
const errorMap = new ErrorMap();  // Map<string, Error> ```

...

Ein besonders nützliches Muster besteht darin, generische Typ-Aliase für Anwendungen von typeof zu erstellen, die Typ-Parameter in Typ-Instanziierungsausdrücken referenzieren:

type BoxFunc<T> = typeof makeBox<T>;  // (value: T) => { value: T }
type Box<T> = ReturnType<typeof makeBox<T>>;  // { value: T }
type StringBox = Box<string>;  // { value: string }

Antwort #2

Dies ist meine derzeit funktionierende Lösung zum Extrahieren nicht exportierter interner Typen von importierten Bibliotheken (wie knex):

// foo is an imported function that I have no control over
function foo<T>(e: T): InternalType<T> {
    return e;
}

class Wrapper<T> {
  // wrapped has no explicit return type so we can infer it
  wrapped(e: T) {
    return foo<T>(e)
  }
}

type FooInternalType<T> = ReturnType<Wrapper<T>['wrapped']>
type Y = FooInternalType<number>
// Y === InternalType<number>

Antwort #3

Wenn Sie einen bestimmten generischen Typ erhalten möchten, können Sie eine Fake-Funktion verwenden, um ihn zu umhüllen.

const wrapperFoo = () => foo<number>()
type Return = ReturnType<typeof wrapperFoo>

Komplexere Demo

function getList<T>(): {
  list: T[],
  add: (v: T) => void,
  remove: (v: T) => void,
  // ...blahblah
}
const wrapperGetList = () => getList<number>()
type List = ReturnType<typeof wrapperGetList>
// List = {list: number[], add: (v: number) => void, remove: (v: number) => void, ...blahblah}

Verwandte Artikel