Question

How to Fix "Cannot use JSX unless the '--jsx' flag is provided" in TypeScript React

typescriptreactjsjsxtsx

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" to tsconfig.json
  • adding an include array

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.json you expect
  • the .tsx file is outside the include paths
  • 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.

Take Quiz

Syntax and Examples

The key TypeScript setting is jsx inside compilerOptions.

Basic syntax

{
  "compilerOptions": {
    "jsx": "react"
  }
}

Common values include:

  • react — classic React JSX transform
  • react-jsx — newer React 17+ transform
  • preserve — 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

  1. It loads tsconfig.json.
  2. It reads include and finds files under lib/.
  3. It sees App.tsx, so it knows this is a TSX file.
  4. It checks compilerOptions.jsx.
  5. Because jsx is 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:

  1. the editor opens App.tsx
  2. TypeScript does not associate it with the expected tsconfig.json
  3. the file may be analyzed in an inferred project with default settings
  4. JSX is not enabled there
  5. 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.

Take Quiz

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.json for shared settings
  • tsconfig.app.json for app files
  • tsconfig.test.json for 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.json taking 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 react for classic React transform
  • use react-jsx for newer React versions
  • use preserve if 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

OptionWhat it meansWhen to use it
jsx: "react"TypeScript understands JSX using the classic React transformOlder React setups or projects still using classic JSX runtime
jsx: "react-jsx"TypeScript uses the newer React JSX runtimeReact 17+ and modern React projects
jsx: "preserve"TypeScript parses JSX but leaves transformation to another toolBabel or another build tool handles JSX output
ToolMain jobImportant note
TypeScriptType checking, editor diagnostics, optional transpilationNeeds tsconfig.json to understand JSX
BabelCode transformationDoes not replace TypeScript project configuration for editor errors
File typeJSX allowed?Notes
.tsNoUse for TypeScript without JSX
.tsxYesUse for TypeScript with JSX

Which jsx value should you choose?

  • Choose react if your project uses the classic React JSX transform.
  • Choose react-jsx if you are using modern React and want the newer runtime.
  • Choose preserve if 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.

Take Quiz

Cheat Sheet

{
  "compilerOptions": {
    "jsx": "preserve"
  }
}

Quick rules

  • JSX in TypeScript requires .tsx files
  • TypeScript must see a valid jsx option
  • The file must be inside the project's include paths
  • Babel config does not replace TypeScript config
  • Editor errors may come from the wrong TypeScript project being loaded

Useful jsx values

  • react → classic React transform
  • react-jsx → modern React transform
  • preserve → keep JSX for Babel or another tool

Debug checklist

  1. Is the file named .tsx?
  2. Is it inside include?
  3. Is there another tsconfig.json nearby?
  4. Does npx tsc --showConfig show the expected config?
  5. Does npx tsc --noEmit reproduce the error?
  6. 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.

Take Quiz

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.json that enables JSX support.
  • Add at least one .tsx component inside the included source folder.
  • Use npx tsc --noEmit to verify that TypeScript can type-check the file.
  • Make sure the setup matches a Babel-style workflow by preventing TypeScript from emitting output.
Take Quiz

Keep learning

Related questions

View more