Menu
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS DSA TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI R GO KOTLIN SASS VUE GEN AI SCIPY CYBERSECURITY DATA SCIENCE INTRO TO PROGRAMMING BASH RUST

TypeScript with React


Why Use TypeScript with React?

TypeScript enhances React with:

  • Type safety for props, state, and context
  • Better IDE autocompletion and refactoring
  • Early error detection during development

Note: This tutorial assumes basic knowledge of React.

If you're new to React, consider checking out our React Tutorial first.


Getting Started

Create a new React + TypeScript app with Vite:

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev

Your tsconfig.json should include these recommended compiler options:

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "Node",
    "jsx": "react-jsx",
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true,
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"]
}

Note: Keep strict enabled for best type safety.

The shown options work well with Vite and Create React App.


Component Typing

Define props with TypeScript and use them in a functional component:

// Greeting.tsx
type GreetingProps = {
  name: string;
  age?: number;
};

export function Greeting({ name, age }: GreetingProps) {
  return (
    <div>
      <h2>Hello, {name}!</h2>
      {age !== undefined && <p>You are {age} years old</p>}
    </div>
  );
}


Common Patterns

Type-Safe Events

Type event handlers for inputs and buttons:

// Input change
function NameInput() {
  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    console.log(e.target.value);
  }
  return <input onChange={handleChange} />;
}

// Button click
function SaveButton() {
  function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
    e.preventDefault();
  }
  return <button onClick={handleClick}>Save</button>;
}

Typing State with useState

Use explicit types for numbers, unions, and nullable values:

const [count, setCount] = React.useState<number>(0);
const [status, setStatus] = React.useState<'idle' | 'loading' | 'error'>('idle');

type User = { id: string; name: string };
const [user, setUser] = React.useState<User | null>(null);

useRef with DOM Elements

Type refs to DOM nodes to access properties safely:

function FocusInput() {
  const inputRef = React.useRef<HTMLInputElement>(null);
  return <input ref={inputRef} onFocus={() => inputRef.current?.select()} />;
}

Children Typing

Accept children with the React.ReactNode type:

type CardProps = { title: string; children?: React.ReactNode };
function Card({ title, children }: CardProps) {
  return (
    <div>
      <h2>{title}</h2>
      {children}
    </div>
  );
}

Fetch Helpers with Generics

Use generics to type API responses:

async function fetchJson<T>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) throw new Error('Network error');
  return res.json() as Promise<T>;
}

// Usage inside an async function/component effect
async function loadPosts() {
  type Post = { id: number; title: string };
  const posts = await fetchJson<Post[]>("/api/posts");
  console.log(posts);
}

Minimal Context and Custom Hook

Provide a small, typed context and a helper hook:

type Theme = 'light' | 'dark';
const ThemeContext = React.createContext<{ theme: Theme; toggle(): void } | null>(null);

function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = React.useState<Theme>('light');
  const value = { theme, toggle: () => setTheme(t => (t === 'light' ? 'dark' : 'light')) };
  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}

function useTheme() {
  const ctx = React.useContext(ThemeContext);
  if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
  return ctx;
}

Vite TypeScript types: Add Vite's ambient types to avoid missing definitions.

// src/vite-env.d.ts
/// <reference types="vite/client" />

Alternatively, add to tsconfig.json:

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

About React.FC: Prefer directly typed function components.

React.FC is optional; it implicitly adds children but isn't required.

Optional baseUrl and paths: These can simplify imports if supported by your bundler.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

Configure only if your tooling (e.g., Vite, tsconfig-paths) is set up for path aliases.


×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
[email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
[email protected]

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2025 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.