What Language Does React Use: Why the Core Is Built in JavaScript Instead of TypeScript
React's core runtime is implemented in plain JavaScript with Flow type annotations, not TypeScript, to ensure direct browser compatibility, minimize build complexity, and maintain the lightweight footprint required by millions of production applications.
When examining the facebook/react repository, one of the first questions developers ask is what language React uses for its core functionality. Despite TypeScript's popularity in modern frontend development, React's engine remains written in plain JavaScript, utilizing the Flow type system for static analysis. This architectural decision reflects historical context, performance constraints, and the library's fundamental requirement to run natively in browsers without additional compilation overhead.
React's Core Implementation Language
The React runtime is implemented in plain JavaScript. If you inspect the source files in packages/react/src/, you'll find standard .js modules rather than .ts files. These modules use the Flow type system for static type checking, indicated by the /* @flow */ comment at the top of core files like ReactBaseClasses.js and ReactHooks.js.
During the build process, the React team uses Babel to strip Flow annotations and transpile modern syntax, producing pure JavaScript bundles that ship directly to npm. This approach provides type safety during development while ensuring consumers receive standard JavaScript that executes immediately in any JavaScript engine.
Why React Uses JavaScript Instead of TypeScript
Several technical and historical factors explain why the React core remains in JavaScript with Flow rather than migrating to TypeScript.
Browser-Native Execution and Runtime Efficiency
JavaScript runs directly in every browser without requiring an additional compilation step. By keeping the core in plain JavaScript, React guarantees the smallest possible runtime overhead and eliminates the need for TypeScript's emit helpers or runtime type checking. The library ships as pre-built bundles that work immediately in Node.js and browsers, maintaining the performance characteristics required by millions of applications.
Historical Context and Flow Adoption
React was created in 2013, predating TypeScript's widespread adoption in the frontend ecosystem. At that time, Facebook had already invested heavily in Flow, a static type checker designed specifically for JavaScript. The React codebase continued with Flow because it allowed incremental adoption of types without rewriting the entire library. Core files like ReactBaseClasses.js and ReactHooks.js still carry /* @flow */ pragmas, reflecting this continuous heritage.
Build Pipeline Simplicity
The React build system uses Babel and Rollup to transform source code. This pipeline already handles JSX transformation, modern syntax transpilation, and Flow type stripping. Introducing TypeScript would require adding the tsc compiler or ts-loader, increasing build complexity and maintenance burden. The current setup strips Flow annotations during the Babel pass, leaving pure JavaScript that Rollup bundles efficiently.
Backward Compatibility and Bundle Size
Shipping pure JavaScript ensures seamless compatibility with all bundlers, including older tools that might struggle with TypeScript-specific outputs. React avoids TypeScript's generated .d.ts declaration files and runtime helpers in the core distribution, keeping the npm package size minimal. This matters for a library downloaded millions of times daily, where every kilobyte affects install times and bundle budgets.
Examining the Source: Key JavaScript Files
The facebook/react repository demonstrates its JavaScript foundation through several critical files in packages/react/src/:
ReactBaseClasses.js
This file defines the fundamental Component and PureComponent classes that power class-based React components. Despite using Flow types, the implementation is pure JavaScript:
/* @flow */
import ReactNoopUpdateQueue from './ReactNoopUpdateQueue';
function Component(props, context, updater) {
this.props = props;
this.context = context;
this.refs = {};
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.setState = function(partialState, callback) {
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
The /* @flow */ pragma enables static type checking during development, but Babel strips these annotations before publishing to npm, leaving standard JavaScript for consumers.
ReactHooks.js
Modern React relies on the Hooks API, implemented in ReactHooks.js. Like other core files, it uses Flow for type safety while remaining JavaScript:
/* @flow */
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
export function useState<S>(initialState: (() => S) | S) {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
Other Critical Files
- ReactJSX.js: Handles JSX runtime helpers used by compiled JSX code
- ReactLazy.js: Implements code-splitting via
React.lazy() - ReactContext.js: Core Context API implementation
- ReactSharedInternalsClient.js and ReactSharedInternalsServer.js: Expose internal objects used by renderers
All these files reside in packages/react/src/ and share the same pattern: JavaScript source with Flow annotations that compile to pure JavaScript for distribution.
Summary
- React's core runtime is implemented in plain JavaScript, not TypeScript, as evidenced by the
.jsfiles inpackages/react/src/. - The codebase uses Flow (
/* @flow */) for static type checking, which Babel strips during the build process to produce pure JavaScript bundles. - JavaScript was chosen over TypeScript for browser-native execution, historical continuity (React predates TypeScript's popularity), build pipeline simplicity (Babel/Rollup vs.
tsc), and backward compatibility with all JavaScript environments. - Key source files like
ReactBaseClasses.jsandReactHooks.jsdemonstrate this architecture, definingComponentclasses and Hooks APIs in JavaScript with Flow type annotations.
Frequently Asked Questions
Why doesn't React use TypeScript for its source code?
React was created in 2013, before TypeScript became the dominant typed language in frontend development. The team chose Flow for static type checking because it integrates directly with JavaScript files using /* @flow */ comments, allowing the codebase to remain plain JavaScript while gaining type safety. Migrating to TypeScript would require significant refactoring of the build pipeline and historical codebase without substantial benefit to the runtime performance.
How does React add type safety without using TypeScript?
React uses Flow, a static type checker developed by Facebook, to add type annotations to JavaScript source files. Files like packages/react/src/ReactBaseClasses.js begin with /* @flow */ and include type signatures (e.g., function Component(props, context, updater) with Flow types). During the build process, Babel strips these annotations, producing pure JavaScript bundles that ship to npm. This approach provides compile-time type checking while maintaining JavaScript as the runtime language.
Can I use TypeScript with React even though React is written in JavaScript?
Yes, TypeScript works excellently with React. While React's core implementation is JavaScript with Flow, the library ships with comprehensive TypeScript declaration files (.d.ts) that provide type definitions for the public API. These definitions allow TypeScript projects to import React with full IntelliSense and compile-time checking. You can write React applications entirely in TypeScript while the underlying library remains JavaScript, demonstrating the flexibility of JavaScript's ecosystem.
What are the performance implications of React using JavaScript instead of TypeScript?
Using plain JavaScript for React's core provides optimal runtime performance because there is no TypeScript compilation overhead or emitted helper code in the final bundles. The build pipeline strips Flow annotations and transpiles modern syntax, but the output is standard JavaScript that executes directly in browsers and Node.js without additional layers. This minimizes bundle size and parse time, which is critical for a library used by millions of applications where every kilobyte affects load performance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →