Backend · Lesson 16

TypeScript
+ Node.js

Build type-safe backend APIs with Express or NestJS — full TypeScript on the server side.

Project Setup

Setting up TypeScript in a Node.js project from scratch.

terminalbash
# Init project & install dependencies
npm init -y
npm install typescript ts-node @types/node --save-dev
npx tsc --init

# Add dev script to package.json
# "dev": "ts-node src/index.ts"
# "build": "tsc"

# Or use tsx for faster restarts
npm install tsx --save-dev
# "dev": "tsx watch src/index.ts"

TypeScript + Express

The most popular Node.js framework — with full TypeScript support via @types/express.

terminal — installbash
npm install express
npm install @types/express --save-dev
src/index.tsTS
import express, { Request, Response, NextFunction } from 'express';

const app = express();
app.use(express.json());

// Type your data shapes
interface User {
  id: number;
  name: string;
  email: string;
}

const users: User[] = [
  { id: 1, name: "Alice", email: "[email protected]" },
];

// GET all users
app.get('/users', (req: Request, res: Response) => {
  res.json(users);
});

// GET user by ID — typed route params
app.get('/users/:id', (req: Request<{ id: string }>, res: Response) => {
  const user = users.find(u => u.id === +req.params.id);
  if (!user) return res.status(404).json({ error: 'Not found' });
  res.json(user);
});

// POST create user — typed request body
app.post('/users', (req: Request<{}, {}, Omit<User, 'id'>>, res: Response) => {
  const newUser: User = { id: users.length + 1, ...req.body };
  users.push(newUser);
  res.status(201).json(newUser);
});

app.listen(3000, () => console.log('Server running on :3000'));

Custom Request & Response Types

Extend Express types to add type safety for params, body, and query.

src/types.tsTS
import { Request } from 'express';

// Typed query params: /search?q=alice&page=2
interface SearchQuery {
  q?: string;
  page?: string;
}

// Typed route params: /users/:id
interface UserParams {
  id: string;
}

// Full typed request: Request<Params, ResBody, ReqBody, Query>
type SearchRequest = Request<{}, {}, {}, SearchQuery>;

app.get('/search', (req: SearchRequest, res: Response) => {
  const { q, page = '1' } = req.query;
  // q is string | undefined  ✅
  // page is string | undefined  ✅
});

Typing Middleware

src/middleware/auth.tsTS
import { Request, Response, NextFunction } from 'express';

// Extend Request to include user data
declare global {
  namespace Express {
    interface Request {
      user?: { id: number; role: string };
    }
  }
}

export function authMiddleware(
  req: Request, res: Response, next: NextFunction
): void {
  const token = req.headers.authorization;
  if (!token) { res.status(401).json({ error: 'Unauthorized' }); return; }

  // attach user to request
  req.user = { id: 1, role: 'admin' };
  next();
}

// Now req.user is typed everywhere ✅
app.get('/profile', authMiddleware, (req: Request, res: Response) => {
  res.json(req.user);  // { id: number; role: string } | undefined
});

NestJS — TypeScript-First Framework

NestJS is built specifically for TypeScript. It uses decorators, modules, and dependency injection — giving you a structured, scalable architecture.

terminalbash
npm install -g @nestjs/cli
nest new my-api
cd my-api && npm run start:dev
users/users.controller.tsTS
import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll() { return this.usersService.findAll(); }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  @Post()
  create(@Body() dto: CreateUserDto) {
    return this.usersService.create(dto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

📌 NestJS generates the full CRUD boilerplate: nest generate resource users creates controller, service, DTOs, and module in one command.

Express vs NestJS

Express
Minimal and flexible. You choose your structure. Great for small APIs and when you need full control.
NestJS
Opinionated and structured. Uses Angular-like architecture. Best for large teams and complex backends.
Fastify
Like Express but faster. Has excellent TypeScript support and a great plugin ecosystem.
Hono
Ultra-lightweight, TypeScript-first, runs on Edge runtimes (Cloudflare Workers, Deno, Bun).
<
Previous
Lesson 15 — TypeScript + React
You are here
16 / 17
Next Lesson
Lesson 17 — Advanced Types