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,JsxFragmentJsxOpeningElement,JsxClosingElement,JsxOpeningFragment,JsxClosingFragmentJsxAttributes,JsxAttribute,JsxSpreadAttributeJsxText,JsxExpression,JsxNamespacedName
Type checking
The checker treats JSX elements as call expressions to a synthetic factory function determined by the JSX mode:
reactmode:React.createElement(tagOrComponent, props, ...children).react-jsxmode:jsx(tagOrComponent, props, key)fromreact/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} />becomesObject.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(...)andjsxs(...).
Language service
JSX gets a few service-specific features:
- Auto-close of opening tags (
autoCloseTag.tsin 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.tsforcheckJsxOpeningLikeElement,getJsxElementClassAttributesType,getResolvedJsxNamespaceForFile. - Factory output —
src/compiler/transformers/jsx.ts. - Pragma handling —
commentPragmasinparser.tsandgetJSXImplicitImportBase/getJSXImportSourceinprogram.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.