您现在的位置是:网站首页 > TypeScript支持与开发实践文章详情
TypeScript支持与开发实践
陈川
【
Node.js
】
46226人已围观
5990字
TypeScript与Express框架的集成基础
Express作为Node.js最流行的Web框架之一,与TypeScript的结合能显著提升开发体验。通过@types/express
类型定义包,我们可以获得完整的类型提示:
npm install express @types/express typescript --save-dev
基础类型化应用示例:
import express, { Request, Response, NextFunction } from 'express';
const app = express();
const port: number = 3000;
interface User {
id: number;
name: string;
}
app.get('/users/:id', (req: Request<{ id: string }>, res: Response<User>) => {
const userId = parseInt(req.params.id);
// 类型系统会检查返回对象是否符合User结构
res.json({ id: userId, name: 'TypeScript User' });
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
中间件的类型安全实现
Express中间件在TypeScript中可以获得完整的类型支持。自定义中间件需要遵循RequestHandler
类型:
import { RequestHandler } from 'express';
const loggerMiddleware: RequestHandler = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
};
const validateUser: RequestHandler<{}, {}, { username: string }> = (req, res, next) => {
if (!req.body.username || req.body.username.length < 3) {
return res.status(400).json({ error: 'Invalid username' });
}
next();
};
app.use(express.json());
app.use(loggerMiddleware);
app.post('/register', validateUser, (req, res) => {
// req.body.username在这里已经被类型检查
});
路由控制的类型化组织
通过TypeScript的模块系统可以更好地组织路由:
// routes/users.ts
import { Router } from 'express';
import { UserService } from '../services/user';
const router = Router();
const userService = new UserService();
router.get('/', async (req, res) => {
const users = await userService.getAll();
res.json(users);
});
router.post('/', async (req, res) => {
const newUser = await userService.create(req.body);
res.status(201).json(newUser);
});
export default router;
然后在主应用中:
// app.ts
import userRouter from './routes/users';
app.use('/api/users', userRouter);
错误处理的类型安全模式
构建类型化的错误处理中间件:
class AppError extends Error {
constructor(
public statusCode: number,
public message: string,
public isOperational = true
) {
super(message);
}
}
const errorHandler: ErrorRequestHandler = (err: AppError, req, res, next) => {
res.status(err.statusCode || 500).json({
status: 'error',
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
});
};
app.get('/error', () => {
throw new AppError(400, 'This is a typed error');
});
app.use(errorHandler);
数据库集成的类型实践
使用TypeORM进行类型安全的数据库操作:
import { Entity, PrimaryGeneratedColumn, Column, createConnection } from 'typeorm';
@Entity()
class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
email: string;
}
const initializeDB = async () => {
const connection = await createConnection({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'test',
password: 'test',
database: 'test',
entities: [User],
synchronize: true
});
const userRepo = connection.getRepository(User);
const newUser = userRepo.create({ name: 'TS User', email: 'ts@example.com' });
await userRepo.save(newUser);
};
配置管理的类型安全方案
使用dotenv
配合类型检查:
import * as dotenv from 'dotenv';
import { z } from 'zod';
dotenv.config();
const envSchema = z.object({
PORT: z.string().transform(Number),
DB_HOST: z.string(),
DB_PORT: z.string().transform(Number),
NODE_ENV: z.enum(['development', 'production', 'test'])
});
const env = envSchema.parse(process.env);
const config = {
port: env.PORT,
db: {
host: env.DB_HOST,
port: env.DB_PORT
},
isDev: env.NODE_ENV === 'development'
};
测试策略的类型化实现
使用Jest进行类型安全的测试:
import request from 'supertest';
import app from '../app';
describe('User API', () => {
it('GET /users should return array of users', async () => {
const res = await request(app)
.get('/api/users')
.expect(200);
// 类型断言
const users: Array<{ id: number; name: string }> = res.body;
expect(users.length).toBeGreaterThan(0);
});
it('POST /users requires valid email', async () => {
await request(app)
.post('/api/users')
.send({ name: 'Test', email: 'invalid' })
.expect(400);
});
});
性能优化的类型安全方法
使用@types/benchmark
进行类型化的性能测试:
import Benchmark from 'benchmark';
import { UserService } from '../services/user';
const suite = new Benchmark.Suite();
const userService = new UserService();
suite
.add('Array#filter', async () => {
await userService.getActiveUsersFilter();
})
.add('Database query', async () => {
await userService.getActiveUsersQuery();
})
.on('cycle', (event: Benchmark.Event) => {
console.log(String(event.target));
})
.run({ async: true });
部署流程的类型检查
创建类型化的部署配置:
interface DeploymentConfig {
target: 'production' | 'staging';
region: string;
memorySize: number;
timeout: number;
environment: Record<string, string>;
}
const config: DeploymentConfig = {
target: 'production',
region: 'us-east-1',
memorySize: 1024,
timeout: 30,
environment: {
NODE_ENV: 'production',
DB_URL: process.env.PROD_DB_URL!
}
};
const validateConfig = (config: DeploymentConfig) => {
if (!config.environment.DB_URL) {
throw new Error('Database URL is required');
}
};
高级类型技巧在Express中的应用
使用条件类型处理动态路由:
type RouteParams<T> = T extends `${string}:${infer Param}/${infer Rest}`
? { [K in Param | keyof RouteParams<Rest>]: string }
: T extends `${string}:${infer Param}`
? { [K in Param]: string }
: {};
function typedRoute<T extends string>(
path: T,
handler: (req: Request<RouteParams<T>>, res: Response) => void
) {
app.get(path, handler);
}
typedRoute('/users/:userId/posts/:postId', (req, res) => {
// req.params自动推断为 { userId: string; postId: string }
const { userId, postId } = req.params;
});
上一篇: GraphQL在Express中的实现