Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript ReturnType of generic function

The new ReturnType in TypeScript 2.8 is a really useful feature that lets you extract the return type of a particular function.

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

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

However, I'm having trouble using it in the context of generic functions.

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

Is there a way extract the return type that a generic function would have given particular type parameters?

like image 651
samfrances Avatar asked May 13 '18 23:05

samfrances


People also ask

What is ReturnType TypeScript?

The ReturnType in TypeScript is a utility type which is quite similar to the Parameters Type. It let's you take the return output of a function, and construct a type based off it.

What are the function of generic types in TypeScript?

TypeScript Generics is a tool which provides a way to create reusable components. It creates a component that can work with a variety of data types rather than a single data type. It allows users to consume these components and use their own types.

How do I pass a TypeScript generic type?

Assigning Generic ParametersBy passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.

Does TypeScript support generic interface?

TypeScript - Generic Interface Here, you will learn about the generic interface in TypeScript. The generic type can also be used with the interface. The following is a generic interface. The above IProcessor is a generic interface because we used type variable <T> .


3 Answers

If you want to get some special generic type, You can use a fake function to wrap it.

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

More complex 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}
like image 170
XGHeaven Avatar answered Oct 18 '22 05:10

XGHeaven


This is my currently working solution for extracting un-exported internal types of imported libraries (like 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>
like image 37
Colin Avatar answered Oct 18 '22 05:10

Colin


This was previously impossible to do in a purely generic fashion, but will be in Typescript 4.7. The pattern is called an "Instantiation Expression". The relevant PR is here. Excerpt from the description:

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> ```

...

A particularly useful pattern is to create generic type aliases for applications of typeof that reference type parameters in type instantiation expressions:

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 }
like image 26
Eric Haynes Avatar answered Oct 18 '22 05:10

Eric Haynes