On this page
TypeScript with Node.js
TypeScript brings type safety to server-side JavaScript. This chapter covers typing Express routes, middleware, and common Node.js patterns.
Project Setup
mkdir my-api && cd my-api
npm init -y
npm install express
npm install --save-dev typescript @types/node @types/express tsx
npx tsc --init
Update tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
Add to package.json:
{
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}
Basic Express Server
// src/index.ts
import express, { Request, Response } from 'express';
const app = express();
app.use(express.json());
app.get('/health', (_req: Request, res: Response) => {
res.json({ status: 'ok' });
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Run with npm run dev.
Typed Route Handlers
interface User {
id: number;
name: string;
email: string;
}
interface CreateUserBody {
name: string;
email: string;
}
const users: User[] = [
{ id: 1, name: 'Alice', email: '[email protected]' }
];
app.get('/users', (_req: Request, res: Response<User[]>) => {
res.json(users);
});
app.post('/users', (req: Request<object, User, CreateUserBody>, res: Response<User>) => {
const { name, email } = req.body;
const user: User = { id: Date.now(), name, email };
users.push(user);
res.status(201).json(user);
});
Generic parameters on Request: Request<P, ResBody, ReqBody, ReqQuery>.
Error Handling
import { NextFunction } from 'express';
interface ApiError {
error: string;
code: number;
}
app.use((err: Error, _req: Request, res: Response<ApiError>, _next: NextFunction) => {
console.error(err.message);
res.status(500).json({ error: 'Internal server error', code: 500 });
});
Build and Deploy
npm run build # compiles src/ → dist/
npm start # runs dist/index.js
TypeScript on the server catches API contract bugs before they reach production. Combine this with the React chapter for full-stack typed development.