question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Type JSX elements based on createElement function

See original GitHub issue

TypeScript currently uses a JSX namespace to type the props of JSX elements. This is customisable by modifying JSX.IntrinsicElements, JSX.ElementClass. However, the type of an element is always JSX.Element.

Of course more interfaces could be added to the JSX namespace. However, I think that with less effort, the compiler could be made more flexible. I’d propose to check JSX elements based on a (virtual) call to JSX.createElement. For instance, the current behaviour can approximately be written like this:

namespace JSX {
  // intrinsic elements
  function createElement<K extends keyof JSX.IntrinsicElements>(tag: K, props: JSX.IntrinsicElements[K], children: JSX.Element[]): JSX.Element;
  // class and functional components
  function createElement<P>(component: (JSX.ElementClass & { new(): { props: P } }) | ((props: P) => JSX.Element), props: P, children: JSX.Element[]): JSX.Element;
}

Given that function signatures are well customisable with the use of generics for instance, most requests can be implemented this way. For instance, #13890 and #13618 would benefit from this change. Libraries that use JSX, but not on the React-way, will benefit from this too.

Proposed semantics

For a JSX element, a virtual call to JSX.createElement is constructed. It is passed three arguments:

  1. Tag name (string) in case of an intrinsic argument (<div />). Otherwise, the identifier is passed (Foo for <Foo />).
  2. An object containing the props.
  3. An array containing the children.

This should be roughly the same as the JSX transform used in the emitter phase. One notable difference is the following: in case of no properties or no children, an empty object or an empty array should be passed, instead ignoring the argument. This makes it easier to write JSX.createElement for library authors.

Backwards compatibility

For backwards compatibility, one of the following approaches could be taken:

  • Use old logic if JSX.createElement does not exist.
  • If JSX.createElement does not exist, default it to (roughly) the definition above.

Error reporting

When type checking the generated function call, the checker can give error messages like "Argument of type … " or “Supplied parameters do not match any signature of call target”. These messages should be replaced when checking JSX elements.

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:138
  • Comments:33 (7 by maintainers)

github_iconTop GitHub Comments

36reactions
niieanicommented, Mar 22, 2017

Having this would allow one to utilize the concept of generalized JSX with TS. Currently it seems impossible, because the return type of any JSX expression is always a non-generic JSX.Element.

In fact, given this it would make sense to ditch the whole “JSX” global namespace and just use the declared type of the locally scoped jsxFactory (set in the tsconfig.json), so that the return type of a JSX expression could be different in every file, based on the implementation of the jsxFactory.

35reactions
m93acommented, May 7, 2019

Could this be added to the roadmap again? Compiler API and JS synergy are both extremely cool, and definitely more important, but this could provide some kick-ass inference with JSX children in much more than just React applications. And it’s a little frustrating to see the dust falling on the PR that should have fixed this a year ago…

Read more comments on GitHub >

github_iconTop Results From Across the Web

JSX In Depth - React
The first part of a JSX tag determines the type of the React element. Capitalized types indicate that the JSX tag is referring...
Read more >
Documentation - JSX - TypeScript
There are two ways to define a value-based element: Function Component (FC); Class Component. Because these two types of value-based elements are ...
Read more >
Proper TypeScript type for creating JSX element from string
First, a bit about JSX. It is just a syntactic sugar for React.createElement , which is ...
Read more >
Functional Components with document.createElement, React ...
var Panel = function Panel(props) { var title = props.title, content = props.content; return React ...
Read more >
How To Create React Elements with JSX - DigitalOcean
Since JSX enables you to also write JavaScript in your markup, you'll be able to take advantage of JavaScript functions and methods, including ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found