Question
How to Fix "Cannot use JSX unless the '--jsx' flag is provided" in TypeScript React
Question
I am getting the TypeScript error "Cannot use JSX unless the '--jsx' flag is provided" while editing .tsx files.
I already tried the common suggestions:
- adding
"jsx": "react"totsconfig.json - adding an
includearray
However, the error still appears.
Here is my tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"allowJs": true,
"checkJs": false,
"jsx": "react",
"outDir": "./build",
"rootDir": "./lib",
"removeComments": true,
"noEmit": true,
"pretty": true,
"skipLibCheck": true,
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": [
"./lib/**/*"
],
"exclude": [
"node_modules"
]
}
I am using Babel 7 to compile the code with the env, react, and typescript presets.
What else could cause this error, and how can I debug it correctly?
Short Answer
By the end of this page, you will understand what the jsx TypeScript setting does, why this error can still appear even when tsconfig.json looks correct, and how to debug common causes such as the wrong project being loaded, files not being included, editor TypeScript issues, and mismatched React/TypeScript configuration.
Concept
TypeScript treats JSX as a special syntax feature. Files such as .tsx contain HTML-like tags inside JavaScript or TypeScript code, so the compiler must be explicitly told how to handle that syntax.
If TypeScript does not see a valid JSX setting, it reports:
Cannot use JSX unless the '--jsx' flag is provided
This usually means one of these things:
- your editor is not using the
tsconfig.jsonyou expect - the
.tsxfile is outside theincludepaths - the file is being treated as part of a different TypeScript project
- the TypeScript server in the editor needs to be restarted
- the compiler configuration is valid, but your toolchain and editor are not reading the same config
A very important point: Babel compiling your code does not automatically control TypeScript's type-checking behavior in your editor. Babel can transform TSX successfully, while TypeScript in the editor still shows errors if its own configuration is wrong or not loaded.
So the real concept here is not just "set jsx to react". It is understanding that:
- Babel transpiles code
- TypeScript checks code and powers editor diagnostics
- both tools may exist in the same project, but they each need correct configuration
In real projects, many JSX errors come from project setup issues rather than syntax mistakes.
Mental Model
Think of your project like a building with multiple security desks.
- Babel is one desk that says: "I know how to transform this code."
- TypeScript is another desk that says: "I know how to analyze this code."
- Your editor is a third desk that asks TypeScript questions in real time.
Even if Babel lets your .tsx file into the building, your editor can still block it if TypeScript was not told that JSX is allowed.
So this error often means: the wrong desk is checking your file, or the right desk does not have the right instructions.
Syntax and Examples
The key TypeScript setting is jsx inside compilerOptions.
Basic syntax
{
"compilerOptions": {
"jsx": "react"
}
}
Common values include:
react— classic React JSX transformreact-jsx— newer React 17+ transformpreserve— keep JSX as-is for another tool like Babel
Example TSX file
import React from 'react';
export function Hello() {
return <h1>Hello</h1>;
}
If this file is inside your TypeScript project and jsx is configured correctly, TypeScript should understand the JSX syntax.
Better config for Babel-based React projects
If Babel is handling the JSX transform, TypeScript often uses preserve:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"jsx": "preserve",
"strict": true,
"noEmit": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["lib/**/*"]
}
This means:
- TypeScript parses and type-checks JSX
- Babel performs the final JSX transformation
Example with React 17+
If you use the newer React transform and want TypeScript aligned with it, you can use:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
That is common in newer React apps.
Step by Step Execution
Consider this project structure:
project/
tsconfig.json
lib/
App.tsx
And this config:
{
"compilerOptions": {
"jsx": "react",
"noEmit": true
},
"include": ["lib/**/*"]
}
And this file:
export function App() {
return <div>Hi</div>;
}
What TypeScript does step by step
- It loads
tsconfig.json. - It reads
includeand finds files underlib/. - It sees
App.tsx, so it knows this is a TSX file. - It checks
compilerOptions.jsx. - Because
jsxis set, it accepts JSX syntax like<div>Hi</div>.
Why the error still happens in real life
Now imagine App.tsx is actually here instead:
project/
src/
App.tsx
But your config still says:
"include": ["./lib/**/*"]
Then TypeScript may not include src/App.tsx in that project.
As a result:
- the editor opens
App.tsx - TypeScript does not associate it with the expected
tsconfig.json - the file may be analyzed in an inferred project with default settings
- JSX is not enabled there
- you get the JSX flag error
Practical debug steps
1. Make sure the file is really .tsx
Correct:
Component.tsx
Wrong:
Component.ts
2. Make sure the file is inside the included paths
If your file is in src/, then this will not include it:
"include": ["./lib/**/*"]
Use something like:
"include": ["lib/**/*", "src/**/*"]
or move the file into lib/.
3. Check whether your editor is using the correct TypeScript project
In editors like VS Code, a file can end up in a different project than expected. Restarting the TypeScript server often helps.
4. Run TypeScript manually
Use:
npx tsc --showConfig
This shows the final resolved config TypeScript is actually using.
You can also run:
npx tsc --noEmit
If the CLI works but the editor still shows the error, the issue is likely editor-side rather than config syntax.
5. Use a JSX mode that matches your setup
If Babel handles JSX output, preserve is often a clean choice:
"jsx": "preserve"
Real World Use Cases
JSX configuration matters in many common setups.
React applications
A React app with TypeScript almost always needs .tsx support for component files:
function Button() {
return <button>Save</button>;
}
Without a proper JSX setting, the editor cannot parse this.
Next.js and frontend frameworks
Frameworks often manage Babel or SWC internally, but TypeScript still needs to understand JSX for type checking and editor support.
Shared component libraries
A design system may contain many .tsx files. If the wrong include path is used, some components may suddenly show JSX errors while others work.
Monorepos
In a monorepo, each package may have its own tsconfig.json. A file may accidentally be opened under the wrong package config, causing this exact error.
Migration from JavaScript to TypeScript
When teams gradually rename files from .js to .tsx, they often forget to update include, rootDir, or editor project boundaries.
Real Codebase Usage
In real projects, developers usually solve this by treating TypeScript configuration as a project boundary problem.
Common patterns
Keep source files under a clear folder
Example:
src/
components/
Then use:
"include": ["src/**/*"]
This reduces confusion about which files belong to the project.
Use noEmit when Babel handles output
If Babel builds the app, TypeScript can focus on type checking only:
{
"compilerOptions": {
"noEmit": true,
"jsx": "preserve"
}
}
Use guard-rail scripts in package.json
{
"scripts": {
"typecheck": "tsc --noEmit"
}
}
This makes it easy to verify whether the config works outside the editor.
Split configs when needed
Larger projects may use:
tsconfig.jsonfor shared settingstsconfig.app.jsonfor app filestsconfig.test.jsonfor tests
This helps avoid files being checked under the wrong rules.
Align React version and JSX mode
Common choices:
- older React style:
jsx: "react" - React 17+:
jsx: "react-jsx" - Babel handles transform:
jsx: "preserve"
Validate project membership
When a file behaves strangely, developers check:
- Is the file inside
include? - Is it excluded accidentally?
- Is the editor using the workspace TypeScript version?
- Is there another nearby
tsconfig.jsontaking precedence?
Common Mistakes
Here are the most common mistakes behind this error.
1. The file is not included in the project
Broken config:
{
"include": ["lib/**/*"]
}
But file location:
src/App.tsx
Fix
Include the correct folder:
{
"include": ["src/**/*", "lib/**/*"]
}
2. Using .ts instead of .tsx
Broken:
App.ts
export function App() {
return <div>Hello</div>;
}
TypeScript expects JSX in .tsx files, not normal .ts files.
Fix
Rename the file:
App.tsx
3. Assuming Babel config fixes TypeScript editor errors
A Babel preset like this:
{
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
}
does not mean TypeScript editor diagnostics are configured correctly.
Fix
Configure tsconfig.json separately and verify the editor is using it.
4. Wrong jsx mode for the project
Not always fatal, but mismatched settings can cause confusion.
Better options
- use
reactfor classic React transform - use
react-jsxfor newer React versions - use
preserveif Babel will transform JSX later
5. Editor TypeScript server cache issues
Sometimes the config is correct, but the editor still shows stale errors.
Fix
- restart the TypeScript server
- reload the editor window
- ensure the workspace TypeScript version is selected
6. Another tsconfig.json is being used
In nested projects, a nearby config file can unexpectedly control a file.
Fix
Search for multiple tsconfig.json files and confirm which one applies.
7. rootDir does not match source layout
Your config uses:
"rootDir": "./lib"
If your .tsx files are elsewhere, that may signal the project is organized differently than the config expects.
Fix
Either move files into lib/ or update the config to match the real source directory.
Comparisons
| Option | What it means | When to use it |
|---|---|---|
jsx: "react" | TypeScript understands JSX using the classic React transform | Older React setups or projects still using classic JSX runtime |
jsx: "react-jsx" | TypeScript uses the newer React JSX runtime | React 17+ and modern React projects |
jsx: "preserve" | TypeScript parses JSX but leaves transformation to another tool | Babel or another build tool handles JSX output |
| Tool | Main job | Important note |
|---|---|---|
| TypeScript | Type checking, editor diagnostics, optional transpilation | Needs tsconfig.json to understand JSX |
| Babel | Code transformation | Does not replace TypeScript project configuration for editor errors |
| File type | JSX allowed? | Notes |
|---|---|---|
.ts | No | Use for TypeScript without JSX |
.tsx | Yes | Use for TypeScript with JSX |
Which jsx value should you choose?
- Choose
reactif your project uses the classic React JSX transform. - Choose
react-jsxif you are using modern React and want the newer runtime. - Choose
preserveif Babel is responsible for transforming JSX later in the build process.
In your kind of setup, where Babel compiles the code, preserve is often the most natural fit.
Cheat Sheet
{
"compilerOptions": {
"jsx": "preserve"
}
}
Quick rules
- JSX in TypeScript requires
.tsxfiles - TypeScript must see a valid
jsxoption - The file must be inside the project's
includepaths - Babel config does not replace TypeScript config
- Editor errors may come from the wrong TypeScript project being loaded
Useful jsx values
react→ classic React transformreact-jsx→ modern React transformpreserve→ keep JSX for Babel or another tool
Debug checklist
- Is the file named
.tsx? - Is it inside
include? - Is there another
tsconfig.jsonnearby? - Does
npx tsc --showConfigshow the expected config? - Does
npx tsc --noEmitreproduce the error? - Did you restart the editor TypeScript server?
Common fix for Babel + TypeScript
{
"compilerOptions": {
"jsx": "preserve",
"noEmit": true
}
}
Common include fix
{
"include": ["src/**/*", "lib/**/*"]
}
FAQ
Why do I still get the JSX flag error even though jsx is in tsconfig.json?
Usually because the file is not part of that TypeScript project, or the editor is not using that config.
Should I use jsx: "react" or jsx: "preserve"?
If Babel transforms JSX, preserve is often best. If TypeScript handles the JSX transform itself, use react or react-jsx depending on your React setup.
Does Babel fix TypeScript editor errors?
No. Babel compiles code, but TypeScript still needs its own configuration for type checking and editor diagnostics.
Can JSX be used in a .ts file?
No. Use .tsx for files containing JSX.
How do I check which TypeScript config is being used?
Run npx tsc --showConfig and inspect the resolved settings. Also check whether your editor is using the workspace TypeScript version.
Why does the error appear only in the editor but not in the build?
Because Babel may compile successfully, while the editor's TypeScript server is using the wrong config or stale project state.
Can include cause JSX errors?
Yes. If the .tsx file is outside the included paths, TypeScript may analyze it without your intended JSX settings.
Mini Project
Description
Create a small React TypeScript setup that demonstrates how TypeScript recognizes JSX only when the file is inside the project and the jsx option is configured correctly. This project helps you practice debugging configuration problems instead of only changing one setting blindly.
Goal
Build a minimal TSX component setup, confirm TypeScript accepts JSX, and verify the project configuration with the TypeScript CLI.
Requirements
- Create a
tsconfig.jsonthat enables JSX support. - Add at least one
.tsxcomponent inside the included source folder. - Use
npx tsc --noEmitto verify that TypeScript can type-check the file. - Make sure the setup matches a Babel-style workflow by preventing TypeScript from emitting output.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.