TypeScript Support and Development Practices
TypeScript, as a superset of JavaScript, provides type safety and modern toolchain support in Express development. When combined with the Express framework, TypeScript can significantly improve the maintainability and development efficiency of backend code, especially in large-scale projects.
Configuration for TypeScript and Express Integration
To use TypeScript in an Express project, the following dependencies must first be installed:
npm install express @types/express typescript --save-dev
Basic tsconfig.json
configuration example:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
Recommended project directory structure:
project/
├── src/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ └── app.ts
├── dist/
├── tsconfig.json
└── package.json
Typed Route Handling
Adding type annotations to route handlers can significantly improve code quality:
import { Request, Response, NextFunction } from 'express';
interface User {
id: number;
name: string;
email: string;
}
app.get('/users/:id',
async (req: Request<{ id: string }>, res: Response<User>, next: NextFunction) => {
const userId = parseInt(req.params.id);
// Type-safe parameter access
const user = await userService.findById(userId);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
}
);
Type-Safe Middleware Implementation
Example of creating typed middleware:
interface AuthenticatedRequest extends Request {
user?: {
id: number;
role: string;
};
}
const authMiddleware = (
req: AuthenticatedRequest,
res: Response,
next: NextFunction
) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
try {
const payload = verifyToken(token);
req.user = {
id: payload.userId,
role: payload.role
};
next();
} catch (err) {
res.status(403).json({ error: 'Invalid token' });
}
};
Typed Error Handling Pattern
Implementing type-safe error handling middleware:
class AppError extends Error {
constructor(
public statusCode: number,
public message: string,
public details?: object
) {
super(message);
}
}
app.use((
err: Error | AppError,
req: Request,
res: Response,
next: NextFunction
) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({
error: err.message,
details: err.details
});
}
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
Type Definitions for Database Models
Using TypeScript interfaces to define Mongoose models:
import { Document, Schema, model } from 'mongoose';
interface IProduct extends Document {
name: string;
price: number;
stock: number;
categories: string[];
}
const productSchema = new Schema<IProduct>({
name: { type: String, required: true },
price: { type: Number, min: 0 },
stock: { type: Number, default: 0 },
categories: { type: [String], index: true }
});
const Product = model<IProduct>('Product', productSchema);
Type-Safe Request Validation Solution
Using zod for runtime validation:
import { z } from 'zod';
const createUserSchema = z.object({
body: z.object({
name: z.string().min(2),
email: z.string().email(),
password: z.string().min(8)
})
});
app.post('/users',
async (req: Request, res: Response, next: NextFunction) => {
try {
const { body } = createUserSchema.parse({
body: req.body
});
// The body is now type-safe and validated
const newUser = await userService.create(body);
res.status(201).json(newUser);
} catch (err) {
next(err);
}
}
);
Dependency Injection Pattern Implementation
Using TypeScript decorators to implement controllers:
import { injectable } from 'inversify';
import { controller, httpGet } from 'inversify-express-utils';
interface IUserService {
findAll(): Promise<User[]>;
}
@injectable()
@controller('/users')
class UserController {
constructor(@inject('UserService') private userService: IUserService) {}
@httpGet('/')
async getAllUsers(req: Request, res: Response) {
const users = await this.userService.findAll();
res.json(users);
}
}
Type Application in Testing
Using Jest for typed testing:
import request from 'supertest';
import app from '../src/app';
describe('User API', () => {
it('GET /users should return user array', async () => {
const response = await request(app)
.get('/users')
.expect(200);
// Type assertion
const users: User[] = response.body;
expect(users).toBeInstanceOf(Array);
users.forEach(user => {
expect(user).toHaveProperty('id');
expect(user).toHaveProperty('name');
});
});
});
Performance Optimization with Type Hints
Leveraging TypeScript's advanced types to reduce runtime checks:
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
function createRoute(
method: HTTPMethod,
path: string,
handler: (req: Request, res: Response) => Promise<void>
) {
app[method.toLowerCase()](path, async (req, res, next) => {
try {
await handler(req, res);
} catch (err) {
next(err);
}
});
}
// Autocomplete is available when using
createRoute('POST', '/products', async (req, res) => {
// Processing logic
});
Type Management for Environment Variables
Strongly typing environment variables:
import dotenv from 'dotenv';
import { z } from 'zod';
dotenv.config();
const envSchema = z.object({
PORT: z.string().transform(Number),
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(['development', 'production', 'test'])
});
const env = envSchema.parse(process.env);
// Now safe to access
const port = env.PORT; // Type is number
Advanced Routing Type Techniques
Using generics to create reusable route types:
type TypedRouteHandler<
P = {},
ResBody = {},
ReqBody = {},
Query = {}
> = (
req: Request<P, ResBody, ReqBody, Query>,
res: Response<ResBody>,
next: NextFunction
) => Promise<void> | void;
const getUserHandler: TypedRouteHandler<
{ id: string },
User,
{},
{ include: string }
> = async (req, res) => {
const user = await userService.findById(req.params.id, {
include: req.query.include
});
res.json(user);
};
Type Handling for Real-Time Applications
Socket.IO integration example with TypeScript:
import { Server } from 'socket.io';
interface ServerToClientEvents {
message: (content: string) => void;
userConnected: (userId: number) => void;
}
interface ClientToServerEvents {
joinRoom: (roomId: string) => void;
sendMessage: (content: string) => void;
}
const io = new Server<ClientToServerEvents, ServerToClientEvents>(httpServer);
io.on('connection', (socket) => {
// Now with full type hints
socket.on('joinRoom', (roomId) => {
socket.join(roomId);
});
socket.emit('message', 'Welcome!');
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn