Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use generics with arrow functions in Typescript/JSX with React?

Using Typescript, typing in Visual Studio, into a ".ts" file, consider the following declaration:

export const foo = <T>(myObject: T) => myObject.toString();

This works fine, type checking is fine, everything is great.

Now place that exact same code into a ".tsx" file that is being used for JSX and React.

Intellisense gets very upset and complains, because it is trying to make the <T> into a React JSX element. But my intention is to have the compiler treat it as a generic type designator.

The compiler complains with:

[gulp-typescript] 17008 JSX element 'T' has no corresponding closing tag.

I have tried numerous syntactical workarounds to try to get both the IDE and the compiler to let me escape the JSX and force the <T> to be understood by the compiler as a generic, as it would if JSX is not in use. But I can't find the magic sauce to do this.

Anyone smarter than I out there who can figure this out?

like image 413
Stephan G Avatar asked Dec 13 '16 01:12

Stephan G


People also ask

How do you use generics with arrow functions in TypeScript?

You can use a generic in an arrow function by setting it right before the function's parameters, e.g. const returnInArray = <T>(value: T): T[] => {} . The generic can then be passed when the function is invoked, e.g. returnInArray<string>('hello') .

How do you use generics in react JS?

Generic Component To use a generic, we simply add the generic parameter between the symbols < and > right after the item and component's props definition, let's call it T, like below. Notice that as long as we apply a generic parameter to our types we need to declare it after all the types usages.

How do generics work in TypeScript?

Generics allow creating 'type variables' which can be used to create classes, functions & type aliases that don't need to explicitly define the types that they use. Generics makes it easier to write reusable code.


2 Answers

When you have a single type parameter, TypeScript isn't sure whether it might be a JSX opening tag or not. It has to choose one, so it goes with JSX.

If you want a function with the exact same semantics, you can explicitly list the constraint of T:

const foo = <T extends {}>(myObject: T) => myObject.toString();

This breaks the ambiguity for TypeScript so that you can use a generic type parameter. It also has the same semantics because type parameters always have an implicit constraint of {}.

like image 186
Daniel Rosenwasser Avatar answered Sep 20 '22 19:09

Daniel Rosenwasser


The usual workaround is to add a trailing comma:

export const foo = <T,>(myObject: T) => myObject.toString();
like image 32
tokland Avatar answered Sep 24 '22 19:09

tokland