Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSX infrastructure? #1637

Open
WorldMaker opened this issue Oct 18, 2023 · 1 comment
Open

JSX infrastructure? #1637

WorldMaker opened this issue Oct 18, 2023 · 1 comment

Comments

@WorldMaker
Copy link

Would it make sense to include some basic low level JSX infrastructure in DOM lib generation?

There's certainly a direct correlation between DOM types and JSX "Intrinsic Element" types in most DOM-targeted implementations. JSX isn't always used in DOM-targeting work (an obvious example is React Native), but a lot of JSX usage in the wild is DOM-targeted and it would be useful to have some reusable, generic infrastructure for JSX DOM types that is generated in a similar, if not exactly the same way, as Typescript's DOM lib and preferably also released together. Some basic mappings for expected HTML tag names and the DOM object properties that most reflect their HTML attributes would be very handy for JSX, and potentially useful even for non-JSX use cases (h factories and other template languages).

Shipping DOM and JSX DOM "base types" together could help mean that things like deprecated properties are reflected in both in the same ways and new properties appear together. (Today the DOM type might reflect an MDN metadata-derived property well in advance of the JSX types being updated.)

(Obviously any auto-generated "base types" for JSX DOM wouldn't directly reflect the needs of any specific JSX implementation, such as React removing innerHTML and substituting its own __dangerouslySetInnerHtml, but using tools like Exclude<Type, Fields> and type unions are easier and safer than hand-maintaining manual types.)

A brief survey of the current "state of the art" for JSX types:

  • @types/react is thousands of lines of types that appear to be hand-maintained by DefinitelyTyped contributors
  • preact/src/jsx.d.ts is similar and appears to be hand-maintained by Preact contributors; there is evidence there may be a "copy-paste relationship" to @types/react, but they are differently formatted documents so how much manual differences there are aren't as easy to spot
  • vue/types/jsx.d.ts leaves the DefinitelyTyped header for @types/react making it explicit there is a direct relationship, but is presumably still merged by hand from time to time by Vue contributors
  • snabbdom/src/jsx.ts gives up and just uses any types (specifically, because it is a couple source files away: export type Props = Record<string, any>;)

Even assuming that this is the entirety of JSX DOM implementations (which it isn't; especially if you presume that more will be written in the future), there's clearly a lot of manual work/rework across this ecosystem. I think that the relationship between DOM types and JSX DOM types are close enough to have a family resemblance and that some of the auto-generation tools that power the DOM types could be put to work improving JSX DOM types for the entire ecosystem. I don't know if the existing MDN metadata is yet enough to build a first pass "base-class" for use with JSX DOM libraries today, but that seems like something that could be explored. I think building and releasing these JSX DOM "base lib" types together with their DOM lib counterparts would be especially great for the overall ecosystem. I realize that JSX is not a standardized part of the JS environment in the same way that the DOM is, but the relationships are so close that it seems unfortunate there aren't existing relationships in the typing infrastructure, too, and if we can find a scope that doesn't feel like too much "creep" that could elevate a lot of the types used daily by many developers.

@WorldMaker
Copy link
Author

Today I discovered HTMLElementTagNameMap, which maybe proves the infrastructure I was looking for was available the whole time and under-utilized in the current ecosystem.

A first pass with trying to use mapped types for this:

  type HtmlElementAttributes<T> = {
    [Property in keyof T as T[Property] extends string | number ? Property : never]?: T[Property]
  }

  type HtmlElements = {
    [Property in keyof HTMLElementTagNameMap]: HtmlElementAttributes<HTMLElementTagNameMap[Property]> & LocalJsxAttributes
  }

With that you can get a starter JSX IntrinsicElements:

declare namespace JSX {
  export interface IntrinsicElements extends HtmlElements {
    // fallback support for non-HTML elements (todo: SVG?)
    [elementName: string]: any
  }
}

I think the part still most needs improvement is that HtmlAttributes map. It still picks up too many extra properties, especially the many all caps constants like ATTRIBUTE_NODE and DOCUMENT_NODE (maybe trying to conditionally detect writable keys?). But this is the sort of start that I was hoping exists and am surprised I've not seen anyone get this close when I surveyed things earlier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant