Skip to Content
Course content

164: TypeScript and JSX Configuration

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've spent any time in a React codebase, you've probably noticed a weird redundancy: every single file that contains a component starts with import React from 'react';. For years, we just accepted this as the cost of doing business. If you forgot that line, the compiler would scream at you because it didn't know how to turn your JSX tags into actual JavaScript function calls. This is exactly where the jsx configuration in your tsconfig.json comes into play.

The manual import headache

The naive way to handle JSX in TypeScript is by setting "jsx": "react". In this mode, TypeScript treats JSX as a direct call to React.createElement(). If you're building a UserDashboard component, the compiler literally replaces your <div> tags with React.createElement('div', ...). Because the output code explicitly references the React object, the React object must be in scope. That's why you're forced to import it in every single file, even if you aren't using any other React hooks or methods in that specific file.

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react"
  }
}

// UserDashboard.tsx
import React from 'react'; // Mandatory, otherwise: "React refers to a UMD global"

export const UserDashboard = () => {
  return <div>Welcome Back!</div>;
};


It feels like boilerplate, and it is. Beyond the annoyance of typing it, it also creates a slight overhead and makes your imports look cluttered. When I'm reviewing code, seeing twenty files with the exact same unused import is just noise.

Letting the compiler do the heavy lifting

The better way—and the way you should be doing it for any modern project—is using "jsx": "react-jsx". This tells TypeScript to use the "new JSX transform" introduced in React 17. Instead of transforming your tags into React.createElement, it transforms them into imports from a special internal package (react/jsx-runtime).

The magic here is that the compiler handles the import for you. You can delete import React from 'react'; from your files entirely, and the code will still run perfectly. I usually spend ten minutes cleaning up a legacy codebase just by changing this one flag and running a global find-and-replace to remove the redundant imports.

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}

// UserDashboard.tsx
// No React import needed here!
export const UserDashboard = () => {
  return <div>Welcome Back!</div>;
};


When you aren't actually using React

Now, here is where things get interesting. What if you're using Preact, or SolidJS, or some other library that uses JSX but isn't React? If you just use react-jsx, your code will try to import from react/jsx-runtime and crash because you don't have React installed.

You might be tempted to go back to the old "jsx": "react" and manually import the factory function, but that's a step backward. Instead, you use jsxImportSource. This allows you to tell TypeScript: "Use the new transform logic, but instead of looking in the 'react' package, look in the 'preact' package." It's the most flexible way to handle JSX because it decouples the syntax from the specific library implementation. I prefer this approach because it keeps the source code clean while giving you total control over the underlying engine.

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact" 
  }
}



📋 Practical Task

Migrating a Legacy UserProfile Component to the Modern JSX Transform

You have been handed a legacy project with a UserProfile.tsx component and a tsconfig.json file. The project is currently using the old JSX transform, forcing developers to manually import React in every file.

Your task:

  1. Modify the tsconfig.json to use the modern react-jsx transform.
  2. Remove the unnecessary import React from 'react'; line from the UserProfile.tsx file without breaking the component.

Starting Code:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "jsx": "react",
    "strict": true
  }
}

// UserProfile.tsx
import React from 'react';

interface Props {
  username: string;
}

export const UserProfile = ({ username }: Props) => {
  return <div>User: {username}</div>;
};
Rating
0 0

There are no comments for now.

to be the first to leave a comment.