33

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?

1

4 Answers 4

37

One workaround is to add a trailing comma:

export const foo = <T,>(myObject: T) => myObject.toString();
Sign up to request clarification or add additional context in comments.

Comments

33

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 {}.

2 Comments

This is a very good solution. Thanks. NOTE: Resharper incorrectly flags this as an error. But it is not.
Don't use this. Nowadays (TS 3.5 and up) the implicit constraint is unknown: devblogs.microsoft.com/typescript/announcing-typescript-3-5/…
5

I personally use extends unknown. Sounds safest to me

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

1 Comment

eslint is not so happy with it. Constraining the generic type T to unknown does nothing and is unnecessary.eslint@typescript-eslint/no-unnecessary-type-constraint
-1

I can't think of a way around that, and will be glad as you to learn of one.
However, here's a different way to achieve the same:

export const foo = function<T>(myObject: T) { return myObject.toString(); }

The compiler won't complain about the generics.

2 Comments

It is true that this will work, but of course it won't behave in every way like an arrow function, and one would have to muck around with the proper binding of "this". But all that said, it may be the only solution. Unfortunately!
There's no this scope when declaring export const

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.