TypeScript Version: 2.2.2 & 2.3.2
Code
// Basic example
const paramArray = <T>(param1: T, param2: T) => [param1, param2];
// React specific example
type Component<T> = React.ComponentClass<T> | React.StatelessComponent<T>;
const decorator = <T>(Component: Component<T>) : Component<T> => (props) => <Component {...props} />
Expected behavior:
Both examples should work in a .tsx
file in addition to the basic example working in a .ts
file.
Actual behavior:
The usage of <T>
prior to the function braces causes a JSX error within .tsx
files: "JSX element .ts
file.
Specifying an unused type variable seems to be a workaround to avoid the error:
const paramArray = <T1, T2>(param1: T1, param2: T1) => [param1, param2];
This is a limitation cased by the use of <T>
for generic type parameter declarations. combined with JSX grammar, it makes such components ambiguous to parse.
The workaround is to use a function expression instead:
// Basic example
const paramArray = function <T>(param1: T, param2: T) { return [param1, param2] };
// React specific example
type Component<T> = React.ComponentClass<T> | React.StatelessComponent<T>;
const decorator = function<T>(Component: Component<T>) : Component<T> { return (props) => <Component {...props} /> };
@mhegazy I can't agree that this a design limitation or that it is ambiguous. It might be harder to parse, but it's definitely possible. Both Babylon and Flow parsers do this correctly. The reason is declaration of a JSX component like <T>
must be followed by either a string literal or a token such as {
, and end with the corresponding JSX closing tag </T>
.
Babel's transpilation of these two cases:
const example1 = <T1>(param1: T1, param2: T1) => [param1, param2]
const example2 = <T1>(param1: T1, param2: T1) => [param1, param2]</T1>
=>
var example1 = function example1(param1, param2) {
return [param1, param2];
};
var example2 = React.createElement(
T1,
null,
"(param1: T1, param2: T1) => [param1, param2]"
);
Could you consider re-opening this as a bug?
In case this helps anyone arriving here, you can use a trailing comma after the type name to get around the ambiguity. For example: const f = <T,>(arg: T): T => {...}
. Thanks to Thomas in this StackOverflow comment for the pointer.
Most helpful comment
In case this helps anyone arriving here, you can use a trailing comma after the type name to get around the ambiguity. For example:
const f = <T,>(arg: T): T => {...}
. Thanks to Thomas in this StackOverflow comment for the pointer.