Description
Initially from a couple different comments, but elaborated here.
Currently, in order to use a generic JSX element, you must alias both the type and interface to a non-generic specialization.
class Select<T> extends React.Component<SelectProps<T>, any> {}
// Alias
type StringSelect = new () => Select<string>
const StringSelect = <StringSelect> Select
const Form = () => <StringSelect items={['a','b']} />
It would be a lot more convenient and consistent to use something like this:
const Form = () => <Select<string> items={['a', 'b']} />
In order to differentiate the latter, you can use a single token of lookahead in the parser to know if it's a generic JSX element:
- If the next token is a
<
, like in< Select <
, then consume the rest of the type as a generic type. After consuming that:- If the next token is a
>
, then finish the type as a generic type cast. - If the next token is an identifier or a
{
(for spread attributes, when they get implemented), then parse the rest as a JSX element. - Otherwise, parse the rest as a type cast.
- If the next token is a
- If the next token is a
>
, like in< Select >
, then finish the type as a simple type cast. - If the next token is an identifier or a
{
, then parse the rest as a JSX element. - Otherwise, consume the rest as a type cast.
I don't know of any reason that wouldn't be feasible to do, considering async arrow functions, which are already implemented, require potentially a whole call expression of parsing to differentiate between let f = async (x, y)
, which is a call expression, and let f = async (x, y) => x
, which is an async arrow function. (I feel sorry for whoever ends up implementing that in V8, which doesn't support any backtracking or much lookahead for memory reasons.)
/cc @RyanCavanaugh