Skip to main content

Setting Up a New React App with TypeScript

Creating a new React project with TypeScript might seem challenging at first, but with the right steps, you can set up a reliable and easy-to-maintain application. This article covers the basics of using Create React App with TypeScript, including setup, configuration, and troubleshooting. We'll discuss why TypeScript is beneficial when working with React and share practical tips and advanced usage scenarios.

Setting Up Create React App with TypeScript

To start a new Create React App project with TypeScript, use the following command:

npx create-react-app my-app --template typescript

After running this command, Create React App configures your project with the necessary typescript npm dependencies and creates starter files with .tsx extensions.

Adding TypeScript to an Existing Create React App Project

To incorporate TypeScript into an existing Create React App project, follow these steps: Install the necessary dependencies:

npm install --save typescript @types/node @types/react @types/react-dom

Rename your files from .js to .tsx (for files containing JSX) or .ts (for plain JavaScript files) Update your package.json to include the TypeScript compiler:

{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
}
}

Create a tsconfig.json file to configure the TypeScript compiler:

{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"outDir": "build",
"jsx": "react-jsx"
},
"include": ["src/**/*"]
}

This configuration enables typescript interface support, strict type checking, and other TypeScript features in your React project.

Configuring TypeScript Paths in Create React App

To set up custom path aliases in TypeScript with Create React App, use the baseUrl and paths options in your tsconfig.json file.

Example:

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

You can then use these aliases in your code:

import Button from '@components/Button';
import { add } from '@utils/math';

For Convex applications, check out our TypeScript best practices for structuring your project effectively.

Managing TypeScript Types in Create React App

When working with typescript types in your React components, you'll often need type definitions for external libraries. Install them using npm:

For example, to install the @types package for React, run:

npm install --save @types/react

You can then use the types in your code:

import * as React from 'react';

interface ButtonProps {
text: string;
onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ text, onClick }) => {
return <button onClick={onClick}>{text}</button>;
};

Resolving TypeScript Errors in Create React App

To fix TypeScript errors in your project, use the error messages to identify issues.

For example, if you encounter an error like this, it's a property type mismatch:

Type '{ foo: string }' is not assignable to type '{ bar: string }'.

You can adjust your code to resolve it:

interface Foo {
foo: string;
}

interface Bar {
bar: string;
}

const foo: Foo = { foo: 'hello' };
const bar: Bar = { bar: 'world' };

Or you may run into missing properties errors:

interface UserProps {
name: string;
age: number;
}

// Error: Property 'age' is missing
const User: React.FC<UserProps> = ({ name, age }) => (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);

// Fix: Include all required properties
<User name="John" age={30} /> // Correct
<User name="John" /> // Wrong

Or you could run into type inference errors:

// Error: Parameter 'event' implicitly has 'any' type
const handleChange = (event) => {
console.log(event.target.value);
};

// Fix: Add proper event type
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
console.log(event.target.value);
};

Using TypeScript Interfaces and Types in Create React App

React components often need type definitions for props and state. Here's how to use TypeScript interfaces effectively:

// Define an interface for component props
interface UserCardProps {
name: string;
email: string;
role: 'admin' | 'user';
lastLogin?: Date; // Optional property
}

// Use the interface in a React component
const UserCard: React.FC<UserCardProps> = ({ name, email, role, lastLogin }) => {
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
<p>Role: {role}</p>
{lastLogin && <p>Last seen: {lastLogin.toLocaleDateString()}</p>}
</div>
);
};

// Define types for component state
type SortOrder = 'asc' | 'desc';
type SortField = 'name' | 'email' | 'role';

interface UserListState {
sortBy: SortField;
order: SortOrder;
searchTerm: string;
}

// Use types in useState
const UserList: React.FC = () => {
const [sorting, setSorting] = useState<UserListState>({
sortBy: 'name',
order: 'asc',
searchTerm: ''
});
};

This setup provides type safety for your components and helps catch common errors during development.

Optimizing TypeScript Build Times in Create React App

Speed up your development workflow with these TypeScript build optimizations:

{
"compilerOptions": {
// Speed up compilation by skipping type checks on node_modules
"skipLibCheck": true,

// Cache compilation results
"incremental": true,

// Specify output for incremental compilation
"tsBuildInfoFile": "./node_modules/.cache/.tsbuildinfo",

// Enable faster lookups
"moduleResolution": "bundler",

// Only check types used in your code
"isolatedModules": true
}
}

You can also speed up your development builds by: Using project references to split your codebase into smaller chunks Setting up path aliases to reduce module resolution time Enabling watch mode during development:

npm start -- --watch

For larger applications, consider implementing code splitting to reduce initial bundle size:

// Instead of direct import
import { ExpensiveComponent } from './ExpensiveComponent';

// Use lazy loading
const ExpensiveComponent = React.lazy(() => import('./ExpensiveComponent'));

function App() {
return (
<Suspense fallback={<Loading />}>
<ExpensiveComponent />
</Suspense>
);
}

Integrating TypeScript with React Components

TypeScript enhances React components by adding type safety to props, state, and events. Here's how to integrate TypeScript with different React patterns:

// Function components with props
interface HeaderProps {
title: string;
subtitle?: string;
onMenuClick: () => void;
}

const Header: React.FC<HeaderProps> = ({ title, subtitle, onMenuClick }) => (
<header>
<h1>{title}</h1>
{subtitle && <h2>{subtitle}</h2>}
<button onClick={onMenuClick}>Menu</button>
</header>
);

// Event handling with TypeScript
const Form: React.FC = () => {
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
};

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
};

return (
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleChange}
placeholder="Enter text"
/>
</form>
);
};

// Using hooks with TypeScript
const Counter: React.FC = () => {
const [count, setCount] = useState<number>(0);
const [items, setItems] = useState<string[]>([]);

useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
};

Integrating API Calls with TypeScript in Create React App

To make API calls in your project, use the fetch API or a library like Axios.

For example, to make a GET request to an API endpoint:

const response = await fetch('https://api.example.com/data');
const data = await response.json();

You can then use the data in your code:

interface Data {
id: number;
name: string;
}

try {
const response = await fetch('https://api.example.com/data');
const data: Data[] = await response.json();
} catch (error) {
console.error('Failed to fetch data:', error);
}

Using TypeScript with React Hooks in Create React App

To use TypeScript with React hooks like useState anduseEffect , leverage TypeScript's type inference while maintaining type safety:

For example, to use the useState hook:

import * as React from 'react';

interface Counter {
count: number;
}

const Counter: React.FC = () => {
const [count, setCount] = React.useState(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};

Final Thoughts on Create React App with TypeScript

TypeScript makes React development more reliable by catching issues early. Here are some next steps to strengthen your TypeScript skills:

  1. Start with basic prop typing in your components

  2. Gradually enable stricter TypeScript checks as you get comfortable

  3. Use the built-in React types before creating custom ones

  4. Keep your TypeScript configs in sync across the team

For more advanced patterns and real-world examples, check out our TypeScript articles and React integration guides.