361
votes

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?

10

10 Answers

467
votes

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;
158
votes

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.

89
votes

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; }
43
votes

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})
               });
           };
35
votes

This works for me

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

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)
9
votes

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;
6
votes

I to 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 keeping 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;
1
votes

In 2021, Ts 4.3.3

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

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