TypeScript with Express

Building type-safe backend applications

⚡ What is TypeScript with Express?

TypeScript brings type safety to Express.js applications, helping you build robust backend APIs with better error handling, autocomplete, and maintainable code for server-side development.


// Basic Express server with TypeScript
import express, { Request, Response } from 'express'

const app = express()

app.get('/', (req: Request, res: Response) => {
  res.send('Hello TypeScript!')
})
                                    

Key Features

🛡️

Type Safety

Catch errors at compile time

interface User {
  id: number
  name: string
}
🔌

Typed Routes

Define routes with type checking

app.get('/user/:id',
  (req, res) => {
  // typed params
})
📝

Middleware Types

Type-safe middleware functions

const logger: 
RequestHandler = 
(req, res, next) => {
  next()
}
🎯

Request/Response

Typed request and response objects

req: Request
res: Response
next: NextFunction

🔹 Basic Express Server Setup

Create a simple Express server with TypeScript:

import express, { Express, Request, Response } from 'express'

const app: Express = express()
const port = 3000

// Middleware
app.use(express.json())

// Basic route
app.get('/', (req: Request, res: Response) => {
  res.json({ message: 'Hello from TypeScript Express!' })
})

// Start server
app.listen(port, () => {
  console.log(`Server running on port ${port}`)
})

Output:

Server running on port 3000

🔹 Typed Route Parameters

Define types for route parameters and query strings:

import { Request, Response } from 'express'

// Define parameter types
interface UserParams {
  id: string
}

// Define query types
interface UserQuery {
  name?: string
  age?: string
}

// Typed route handler
app.get('/user/:id', 
  (req: Request<UserParams, {}, {}, UserQuery>, res: Response) => {
    const userId = req.params.id
    const userName = req.query.name
    
    res.json({ 
      id: userId, 
      name: userName 
    })
  }
)

🔹 Typed Request Body

Create type-safe POST requests with body validation:

import { Request, Response } from 'express'

// Define request body type
interface CreateUserBody {
  name: string
  email: string
  age: number
}

// POST route with typed body
app.post('/users', 
  (req: Request<{}, {}, CreateUserBody>, res: Response) => {
    const { name, email, age } = req.body
    
    // TypeScript knows the types!
    const newUser = {
      id: Date.now(),
      name,
      email,
      age
    }
    
    res.status(201).json(newUser)
  }
)

🔹 Custom Middleware with Types

Create reusable typed middleware functions:

import { Request, Response, NextFunction, RequestHandler } from 'express'

// Logger middleware
const logger: RequestHandler = (
  req: Request, 
  res: Response, 
  next: NextFunction
) => {
  console.log(`${req.method} ${req.path}`)
  next()
}

// Auth middleware
const authenticate: RequestHandler = (req, res, next) => {
  const token = req.headers.authorization
  
  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  
  next()
}

// Use middleware
app.use(logger)
app.get('/protected', authenticate, (req, res) => {
  res.json({ message: 'Protected route' })
})

🔹 Error Handling with Types

Implement type-safe error handling:

import { Request, Response, NextFunction, ErrorRequestHandler } from 'express'

// Custom error class
class AppError extends Error {
  statusCode: number
  
  constructor(message: string, statusCode: number) {
    super(message)
    this.statusCode = statusCode
  }
}

// Error handling middleware
const errorHandler: ErrorRequestHandler = (
  err: AppError,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const statusCode = err.statusCode || 500
  const message = err.message || 'Internal Server Error'
  
  res.status(statusCode).json({
    error: message,
    statusCode
  })
}

// Use error handler
app.use(errorHandler)

🧠 Test Your Knowledge

What is the correct type for Express request handler?