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?
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') .
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.
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.
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 {}
.
The usual workaround is to add a trailing comma:
export const foo = <T,>(myObject: T) => myObject.toString();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With