JSX is an XML-like syntax embedded in code. TypeScript checks it and can compile it. A
file must have the .tsx extension to use it, and the jsx option
must be set
(Handbook: JSX). Parsing
differences are on the
Lexical structure page.
Emit modes
jsx | Output for <div /> | Extension | Use |
|---|---|---|---|
preserve | <div /> | .jsx | A later tool transforms the JSX |
react-native | <div /> | .js | As preserve, but with a .js extension |
react | React.createElement("div") | .js | The classic transform |
react-jsx | _jsx("div", {}) | .js | The automatic runtime |
react-jsxdev | _jsxDEV("div", …) | .js | The automatic runtime, in development |
The classic transform calls a factory function that must be in scope, by default
React.createElement, and can be changed with jsxFactory.
jsxFragmentFactory does the same for fragments. The automatic runtime
imports its functions from ${jsxImportSource}/jsx-runtime by itself, and
jsxImportSource defaults to react. A file that uses JSX under
these runtimes counts as a module in moduleDetection: auto.
/** @jsx h */
/** @jsxFrag Frag */
import { h, Frag } from "./runtime";
const a = <div id="x">text</div>;
const b = <><div /></>;
const a = h("div", { id: "x" }, "text");
const b = h(Frag, null,
h("div", null));
Pragmas
A comment at the top of a file can set the JSX options for that file alone.
| Comment | Sets |
|---|---|
/** @jsx h */ | The factory function, as jsxFactory |
/** @jsxFrag Frag */ | The fragment factory, as jsxFragmentFactory |
/** @jsxImportSource preact */ | The automatic runtime package, as jsxImportSource |
/** @jsxRuntime classic */ | The transform: classic or automatic |
The JSX namespace
All checking is driven by a namespace called JSX, which a framework
provides. For the classic transform the compiler looks for it on the factory’s top-level
name, such as React.JSX or h.JSX. For the automatic runtime it
looks for an export from ${jsxImportSource}/jsx-runtime. If it is not found,
both fall back to a global JSX.
| Member | Purpose |
|---|---|
JSX.IntrinsicElements | The lower-case tags and their attributes. Without it, intrinsic elements are not checked |
JSX.Element | The result type of a JSX expression. Otherwise any |
JSX.ElementType | What is valid as a tag (5.1). Lets a library allow, for example, a component that returns a Promise |
JSX.ElementClass | The type that a class component’s instances must fit |
JSX.ElementAttributesProperty | The instance property that holds a class component’s attributes |
JSX.ElementChildrenAttribute | The attribute that holds children |
JSX.IntrinsicAttributes | Extra attributes available on components, such as key |
JSX.IntrinsicClassAttributes<T> | Extra attributes for class components |
Elements
A tag starting with a lower-case letter is an intrinsic element, looked up in
JSX.IntrinsicElements. A tag starting with an upper-case letter is a
value-based element, an identifier in scope. The compiler tries it as a function
component, then as a class component.
declare namespace JSX {
type Element = { el: true };
interface IntrinsicElements {
foo: { required: string; optional?: number };
}
interface IntrinsicAttributes { key?: string }
}
<foo required="x" />; // fine
<foo />; // error: required is missing
<foo required={1} />; // error: wrong type
<foo required="x" other={1} />; // error: unknown attribute
<foo required="x" data-any={1} />; // fine: names with a hyphen are not checked
<bar />; // error: not an intrinsic element
declare const props: { required: string };
<foo {...props} />; // spread is checked too
JSX.IntrinsicElementsA function component takes its props as the first argument, and must return something
assignable to JSX.Element. Overloads are allowed. A component’s type
parameters can be inferred from its attributes, or given directly.
function List<T>(props: { items: T[]; show: (x: T) => string }) { return null as any; }
const a = <List items={[1, 2]} show={n => n.toFixed()} />; // T is number
const b = <List<string> items={[]} show={s => s} />; // T given explicitly
Expressions between { and } are checked as usual. Children are
passed through the property named by JSX.ElementChildrenAttribute, and can be
typed as any other prop.