Andreas Frische
Andreas Frische

Reputation: 9941

What is the syntax for Typescript arrow functions with generics?

The typescript handbook currently has nothing on arrow functions. Normal functions can be generically typed with this syntax: example:

function identity<T>(arg: T): T {
    return arg;
}

What is the syntax for arrow functions?

Upvotes: 804

Views: 494144

Answers (18)

Yuh Lee
Yuh Lee

Reputation: 353

Here I got 2 cases of arrow function with generics:

  • To call directly:
const foo = <T>(value: T): void => {
    console.log(value);
}
foo('hello') // hello
  • To create a type to use later:
type TFoo<S> = (value: S) => boolean;
const foo: TFoo<number> = (value) => value>0;
console.log(foo(1)) // true
console.log(foo(-1)) // false

Hopefully this helps somewhere!

Upvotes: -3

Aditya parmar
Aditya parmar

Reputation: 31

type TypeCbFoo = <T>(x: T) => T;
const foo: TypeCbFoo = (x) => x;

with useCallback

const foo2 = useCallback<TypeCbFoo>((x) => x, []);

inline

const foo: <T>(x: T) => T = (x) => x;

Upvotes: 3

Robin Luiten
Robin Luiten

Reputation: 5328

I found the example above confusing. I am using React and JSX so I think it complicated the scenario.

I got clarification from TypeScript Deep Dive, which states for arrow generics:

Workaround: Use extends on the generic parameter to hint the compiler that it's a generic, this came from a simpler example that helped me.

const identity = < T extends {} >(arg: T): T => { return arg; }

Upvotes: 117

const.takeo
const.takeo

Reputation: 289

This works for me

const logSomething = <T>(something:T): T => {
    return something;
}

Upvotes: 24

LearnToLive
LearnToLive

Reputation: 511

I know I am late to this answer. But thought of answering this in case anyone else finds it helpful. None of the answers mention how to use generics with an async arrow function.

Here it goes :

const example = async <T> (value: T) => {
    //awaiting for some Promise to resolve or reject;
     const result = await randomApi.getData(value);
} 

Upvotes: 7

Ester Kaufman
Ester Kaufman

Reputation: 868

Adding an example for multiple depended generic types:

This function, was converted to arrow function as the following:

http.get = function <T = any, R = AxiosResponse<T>>(
    url: string,
    config?: AxiosRequestConfig
): Promise<R> {
    config.withCredentials = true;
    ....
};

Notice the extends instead of the equal sign:

http.get = async <T extends any, R extends unknown = AxiosResponse<T>>(
    url: string,
    config?: AxiosRequestConfig
): Promise<R> => {
    config.withCredentials = true;
    ...
};

Upvotes: 2

Honshu
Honshu

Reputation: 13

const identity = <T>(arg: T): T {
    return arg;
}

Upvotes: 0

Roy Art
Roy Art

Reputation: 703

I use this type of declaration:

const identity: { <T>(arg: T): T } = (arg) => arg;

It allows defining additional props to your function if you ever need to, and in some cases, it helps keep the function body cleaner from the generic definition.

If you don't need the additional props (namespace sort of thing), it can be simplified to:

const identity: <T>(arg: T) => T = (arg) => arg;

Upvotes: 14

Suhaib
Suhaib

Reputation: 27

If need make return method generic, it didn't show errors with extra data ex:

export type DataGenerator<T> = (props: {name: string}) => T;

const dataGenerator: DataGenerator<{city?: string}> = ({  name }) => {
    return {
        city: `${name}`,
        name: "aaa",
    }
}

dataGenerator({name: "xxx"})

I need to show error on name

Upvotes: -3

Archimedes Trajano
Archimedes Trajano

Reputation: 41580

The non-arrow function way. Expanding on the example from the OP.

function foo<T>(abc: T): T {
    console.log(abc);
    return abc;
}

const x = { abc: 123 };
foo(x);

const y = 123;
foo<number>(y);

Aside from the answer of embedding the whole thing into one statement:

const yar = <T,>(abc: T) => {
    console.log(abc);
    return abc;
}

Another approach is to have an intermediate type:

type XX = <T>(abc: T) => T;

const bar: XX = (abc) => {
    console.log(abc);
    return abc;
}

Playground

Upvotes: 12

jbmilgrom
jbmilgrom

Reputation: 23291

Edit

Per @Thomas comment, in newer TS compilers, we can simply do:

const foo = <T,>(x: T) => x;

Original Answer

The full example explaining the syntax referenced by Robin... brought it home for me:

Generic functions

Something like the following works fine:

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

However using an arrow generic function will not:

const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag

Workaround: Use extends on the generic parameter to hint the compiler that it's a generic, e.g.:

const foo = <T extends unknown>(x: T) => x;

Upvotes: 1144

Nkoro Joseph Ahamefula
Nkoro Joseph Ahamefula

Reputation: 530

enter image description here

Using <T, extends {}> throws an error when you try to pass null as parameter. I will prefer using <T,> because it clears the issue. I am yet to get the reason why. But this worked for me.

enter image description here

Upvotes: -2

CodeFarmer
CodeFarmer

Reputation: 2706

In 2021, Ts 4.3.3

const useRequest = <DataType, ErrorType>(url: string): Response<DataType, ErrorType> 
   => {
      ...
   }

Upvotes: 2

Bear
Bear

Reputation: 317

so late, but with ES6 no need extends it still work for me.... :)

let getArray = <T>(items: T[]): T[] => {
    return new Array<T>().concat(items)
}

let myNumArr = getArray<number>([100, 200, 300]);
let myStrArr = getArray<string>(["Hello", "World"]);
myNumArr.push(1)
console.log(myNumArr)

Upvotes: 27

Michal Filip
Michal Filip

Reputation: 990

while the popular answer with extends {} works and is better than extends any, it forces the T to be an object

const foo = <T extends {}>(x: T) => x;

to avoid this and preserve the type-safety, you can use extends unknown instead

const foo = <T extends unknown>(x: T) => x;

Upvotes: 12

mb21
mb21

Reputation: 39478

If you're in a .tsx file you cannot just write <T>, but this works:

const foo = <T, >(x: T) => x;

As opposed to the extends {} hack, this hack at least preserves the intent.

Upvotes: 357

Harshit Singhai
Harshit Singhai

Reputation: 1288

This works for me

const Generic = <T> (value: T) => {
    return value;
} 

Upvotes: 64

Andreas Frische
Andreas Frische

Reputation: 9941

The language specification says on p.64f

A construct of the form < T > ( ... ) => { ... } could be parsed as an arrow function expression with a type parameter or a type assertion applied to an arrow function with no type parameter. It is resolved as the former[..]

example:

// helper function needed because Backbone-couchdb's sync does not return a jqxhr
let fetched = <
           R extends Backbone.Collection<any> >(c:R) => {
               return new Promise(function (fulfill, reject) {
                   c.fetch({reset: true, success: fulfill, error: reject})
               });
           };

Upvotes: 52

Related Questions