74

Typescript introduces support for the JSX syntax. So I have an expression that works quite well with traditional *.ts files but no with *.tsx ones:

const f = <T1>(arg1: T1) => <T2>(arg2: T2) => {
   return { arg1, arg2 };
}

I wonder is there a way to make it work inside a *.tsx file?

1

2 Answers 2

132

To get it to understand it's a type parameter and not a JSX element, you can add a comma after the type parameter:

const f = <T1,>(arg1: T1) => <T2,>(arg2: T2) => {
   return { arg1, arg2 };
};

Or you could use function expressions instead:

const f = function<T1>(arg1: T1) {
    return function<T2>(arg2: T2) {
        return { arg1, arg2 };
    };
};

Or alternatively, in this scenario, this works:

const f = <T1, T2>(arg1: T1) => (arg2: T2) => {
   return { arg1, arg2 };
};
Sign up to request clarification or add additional context in comments.

3 Comments

I've also found that just adding a comma works, which seems to be the best solution for me. It seems like it just hints to TS that this is a generic rather than a JSX element, without actually changing any functionality. There's even been specific prettier updates to allow this particular trailing comma: github.com/prettier/prettier/issues/6114
@Jasper36 yes, that is the recommended way of doing it from my understanding. It was in the answer, but I've moved it to the top now.
You can also add a type constraint, like <T extends string>
56

This is a result of parsing ambiguity issues. One thing that would make this unambiguous is adding an explicit constraint on T1.

const f = <T1 extends unknown>(arg1: T1) => {
    return { arg1 };
}

Type parameters like T1 implicitly have a constraint of unknown anyway, so in this case your code is functionally equivalent.

Take this solution and you can apply on each arrow function from your original example.

5 Comments

It should've been extends any
I work on the team and no it shouldn't have. As I explained above, generics without a constraint get an implicit constraint of {}, and for the most part are functionally equivalent.
@DanielRosenwasser I've run into a lot of trouble trying to use extends {} because in that case your function wouldn't accept something pretty common like React.ReactNode (which can be null). Are there any gotchas with using <T, Dummy>? So far seems to be working ok but wanted to make sure. This one sounds the cleanest to me, and makes explicit the reason why it's not just T.
With TypeScript 3.0 you can use extends unknown and I think that should work.
Unfortunately now Eslint reports error Constraining the generic type STATE to unknown does nothing and is unnecessary @typescript-eslint/no-unnecessary-type-constraint

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.