Open-Source Wikis

/

TypeScript

/

Features

/

JSX

microsoft/TypeScript

JSX

The compiler's support for .jsx / .tsx syntax — scanning, parsing, type-checking, and transforming JSX into either createElement-flavoured or jsx-runtime calls.

Where JSX touches the codebase

Subsystem File Role
Scanner src/compiler/scanner.ts LanguageVariant.JSX toggle; JsxText, JsxTextAllWhiteSpaces, LessThanSlashToken
Parser src/compiler/parser.ts parseJsxElementOrSelfClosingElementOrFragment, JSX-vs-< disambiguation
Checker src/compiler/checker.ts Resolution of JSX.IntrinsicElements, JSX.Element, JSX.LibraryManagedAttributes, etc.
Transformer src/compiler/transformers/jsx.ts (~36k lines) <Foo />createElement(Foo) or jsx(Foo)
Language service various JSX-specific completions, attribute hints, document highlights

--jsx modes

Mode Behaviour
preserve Pass JSX through untouched (.jsx output); for downstream tooling
react Classic transform → React.createElement(...)
react-jsx New automatic runtime → imports jsx/jsxs from react/jsx-runtime
react-jsxdev Dev variant of the new runtime → jsxDEV with line/column metadata
react-native Like preserve but emits .js and rewrites JSX as required

compilerOptions.jsxFactory, jsxFragmentFactory, and jsxImportSource further customise the emitted form. The @jsxRuntime, @jsxImportSource, @jsxFrag, and @jsx pragma comments at the top of a file override the global settings per-file.

Scanning and parsing

JSX is grammatically ambiguous with TypeScript type assertions and arrow-function generics in .tsx files. The scanner uses LanguageVariant.JSX to decide token interpretation; the parser uses lookAhead/tryParse to commit to JSX or fall back to a generic-arrow expression. JSX text inside elements is scanned by a sub-mode that produces JsxText and JsxTextAllWhiteSpaces tokens.

The parser produces these node kinds (all defined in src/compiler/types.ts):

  • JsxElement, JsxSelfClosingElement, JsxFragment
  • JsxOpeningElement, JsxClosingElement, JsxOpeningFragment, JsxClosingFragment
  • JsxAttributes, JsxAttribute, JsxSpreadAttribute
  • JsxText, JsxExpression, JsxNamespacedName

Type checking

The checker treats JSX elements as call expressions to a synthetic factory function determined by the JSX mode:

  • react mode: React.createElement(tagOrComponent, props, ...children).
  • react-jsx mode: jsx(tagOrComponent, props, key) from react/jsx-runtime.

Two predefined namespaces live in JSX.* (declared by @types/react or by the user):

  • JSX.IntrinsicElements — string-named elements (<div />).
  • JSX.Element — the return type of every JSX expression.
  • JSX.LibraryManagedAttributes, JSX.IntrinsicAttributes, JSX.IntrinsicClassAttributes — for prop-type computation.

The checker resolves an element's tag, looks up the appropriate component or intrinsic type, computes the expected props type, and checks each attribute against it. JSX children are checked as if assigned to the children prop.

Transform

src/compiler/transformers/jsx.ts is selected when --jsx is anything other than preserve / react-native. It walks the tree replacing JSX nodes with the chosen factory call. The new automatic runtime (react-jsx/react-jsxdev) inserts import { jsx, jsxs, Fragment } from "react/jsx-runtime" (or the user-specified import source) at the top of any file that uses JSX.

Key implementation details:

  • Whitespace handling. The transformer mimics the React runtime's whitespace-collapsing rules so output behaves like a hand-written call.
  • Spread props. <Foo {...props} a={1} /> becomes Object.assign({}, props, { a: 1 }) (legacy) or the runtime's spread-aware constructor (new runtime).
  • Children flattening. Single child vs. children array is the runtime-distinguishing detail between jsx(...) and jsxs(...).

Language service

JSX gets a few service-specific features:

  • Auto-close of opening tags (autoCloseTag.ts in fourslash tests).
  • Attribute completions sourced from the resolved component's prop type.
  • "Hover" of intrinsic tags shows the IntrinsicElements entry.
  • Component prop renames are propagated correctly across JSX usages.

Tests

JSX tests live under tests/cases/conformance/jsx/ (compiler tests) and tests/cases/fourslash/ (fourslash tests with names containing jsx). The conformance directory contains hundreds of small cases that pin JSX-mode behaviour, intrinsic element matching, factory-call shapes, and edge cases like spread attributes.

Entry points for modification

  • Tag dispatch and prop-type resolution — search checker.ts for checkJsxOpeningLikeElement, getJsxElementClassAttributesType, getResolvedJsxNamespaceForFile.
  • Factory output — src/compiler/transformers/jsx.ts.
  • Pragma handling — commentPragmas in parser.ts and getJSXImplicitImportBase/getJSXImportSource in program.ts.

See systems/transformers for the broader transform pipeline.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

JSX – TypeScript wiki | Factory