bugl
bugl
HomeLearnPatternsPathsSearch
HomeLearnPatternsPathsSearch

Loading lesson path

Learn/TypeScript/TypeScript Core
TypeScript•TypeScript Core

TypeScript with React

Flash cards

Review the key moves

1/4
Core idea

What is the main idea behind TypeScript with React?

Lesson checks

Practice each idea before moving on

Short Mimo-style checks built from this lesson's code, terms, and sequence.

1Quick choice

Which statement best captures the main point of this lesson?

2Fill blank

Complete the missing token from the example code.

___ create vite@latest my-app -- --template react-ts
3Order

Put the learning moves in the order that makes the concept easiest to apply.

useRef with DOM Elements
Typing State with useState
Why Use 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:

Example

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:

Example

{
 "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:

Example

// 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>
);
}

Type-Safe Events

Type event handlers for inputs and buttons:

Example

// 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:

Example

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:

Example

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:

Example

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

Fetch Helpers with Generics

Example

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:

Example

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.

Example

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

Alternatively, add to tsconfig.json :

Example

{
 "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.

Example

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

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

Previous

TypeScript with Node.js

Next

TypeScript Tooling