TypeScript支持与开发实践
TypeScript作为JavaScript的超集,在Express开发中提供了类型安全和现代工具链支持。结合Express框架,TypeScript能够显著提升后端代码的可维护性和开发效率,尤其在大型项目中表现突出。
TypeScript与Express的集成配置
在Express项目中使用TypeScript需要先安装必要的依赖:
npm install express @types/express typescript --save-dev
基础tsconfig.json配置示例:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
典型项目目录结构建议:
project/
├── src/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ └── app.ts
├── dist/
├── tsconfig.json
└── package.json
类型化路由处理
为路由处理器添加类型注解可以显著提升代码质量:
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);
// 类型安全的参数访问
const user = await userService.findById(userId);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
}
);
中间件的类型安全实现
创建类型化中间件示例:
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' });
}
};
错误处理的类型化模式
实现类型安全的错误处理中间件:
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' });
});
数据库模型的类型定义
使用TypeScript接口定义Mongoose模型:
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);
请求验证的类型安全方案
使用zod进行运行时验证:
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
});
// 此时body已通过类型安全验证
const newUser = await userService.create(body);
res.status(201).json(newUser);
} catch (err) {
next(err);
}
}
);
依赖注入的模式实现
使用TypeScript装饰器实现控制器:
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);
}
}
测试中的类型应用
使用Jest进行类型化测试:
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);
// 类型断言
const users: User[] = response.body;
expect(users).toBeInstanceOf(Array);
users.forEach(user => {
expect(user).toHaveProperty('id');
expect(user).toHaveProperty('name');
});
});
});
性能优化与类型提示
利用TypeScript的高级类型减少运行时检查:
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);
}
});
}
// 使用时获得自动补全
createRoute('POST', '/products', async (req, res) => {
// 处理逻辑
});
环境变量的类型管理
强类型处理环境变量:
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);
// 现在可以安全访问
const port = env.PORT; // 类型为number
高级路由类型技巧
使用泛型创建可复用路由类型:
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);
};
实时应用的类型处理
Socket.IO与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) => {
// 现在有完整的类型提示
socket.on('joinRoom', (roomId) => {
socket.join(roomId);
});
socket.emit('message', 'Welcome!');
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn