Skip to content

Add JSX support in type definition #3

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

Merged
merged 11 commits into from
Dec 9, 2020
67 changes: 61 additions & 6 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
// TypeScript Version: 3.7

import {Element, Node, Root} from 'xast'
import * as xast from 'xast'

type Children = string | Node | number | Children[]
type Children = string | xast.Node | number | Children[]

type Primitive = null | undefined | string | number

/**
* Extending Attributes to Support JS Primitive Types
*/
type Attributes = Record<string, Primitive>
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
interface Attributes {
[attribute: string]: Primitive
}

/**
* Create XML trees in xast.
*
* @param name Qualified name. Case sensitive and can contain a namespace prefix (such as rdf:RDF).
* @param children (Lists of) child nodes. When strings are encountered, they are mapped to Text nodes.
*/
declare function xastscript(name: string, ...children: Children[]): Element
declare function xastscript(name: string, ...children: Children[]): xast.Element

/**
* Create XML trees in xast.
*
* @param name Qualified name. Case sensitive and can contain a namespace prefix (such as rdf:RDF).
* @param children (Lists of) child nodes. When strings are encountered, they are mapped to Text nodes.
*/
declare function xastscript(name: null, ...children: Children[]): Root
declare function xastscript(name: null, ...children: Children[]): xast.Root

/**
* Create XML trees in xast.
Expand All @@ -38,6 +41,58 @@ declare function xastscript(
name: string,
attributes?: Attributes,
...children: Children[]
): Element
): xast.Element

/**
* This unique symbol is declared to specify they key on which JSX children are passed, without conflicting
* with the Attributes type.
*/
declare const children: unique symbol

/**
* This namespace allows to use `xastscript` as a JSX implementation.
*
* This namespace is only used to support the use as JSX. It’s **not** intended for direct usage.
*/
declare namespace xastscript.JSX {
/**
* This defines the return value of JSX syntax.
*/
type Element = xast.Element

/**
* This disallows the use of
*/
type IntrinsicAttributes = never

/**
* This defines the prop types for known elements.
*
* For `xastscript` this defines any string may be used in combination with `xast` `Attributes`.
*
* This **must** be an interface.
*/
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
interface IntrinsicElements {
[tagName: string]:
| Attributes
| {
/**
* The prop that matches `ElementChildrenAttribute` key defines the type of JSX children, defines the children type.
*/
[children]?: Children
}
}

/**
* The key of this interface defines as what prop children are passed.
*/
interface ElementChildrenAttribute {
/**
* Only the key matters, not the value.
*/
[children]?: any
}
}

export = xastscript
50 changes: 50 additions & 0 deletions types/test-jsx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {Element} from 'xast'
import x = require('xastscript')

const xmlns = 'http://www.sitemaps.org/schemas/sitemap/0.9'

let jsx
// $ExpectType Element
jsx = <urlset />
// $ExpectType Element
jsx = <urlset xmlns={xmlns} />
// $ExpectType Element
jsx = <urlset>string</urlset>
// $ExpectType Element
jsx = <urlset>{['string', 'string']}</urlset>
// $ExpectType Element
jsx = (
<urlset xmlns={xmlns}>
<child />
</urlset>
)
// $ExpectType Element
jsx = (
<urlset>
<loc />
string
</urlset>
)
// $ExpectType Element
jsx = (
<urlset>
<loc />
</urlset>
)
// $ExpectType Element
jsx = (
<urlset>
<loc />
<loc />
</urlset>
)
// $ExpectType Element
jsx = <urlset>{[<loc />, <loc />]}</urlset>
// $ExpectType Element
jsx = <urlset>{[]}</urlset>

jsx = <foo invalid={{}}></foo> // $ExpectError
jsx = <foo>{{invalid: 'child'}}</foo> // $ExpectError

declare function Bar(props?: Record<string, unknown>): Element
const bar = <Bar /> // $ExpectError
2 changes: 2 additions & 0 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
"jsx": "react",
"jsxFactory": "x",
"lib": ["es2015"],
"noImplicitAny": true,
"noImplicitThis": true,
Expand Down