第11章 Node.js 后端开发:TypeScript的全栈力量
🚀 全栈开发新境界:TypeScript不仅在前端大放异彩,在后端开发中更是展现出强大威力。本章将带你掌握如何使用TypeScript构建健壮、类型安全的Node.js后端应用。
🎯 11.1 NestJS:企业级TypeScript后端框架
💡 NestJS:Node.js中最强大的企业级框架,完美支持TypeScript的类型系统,让后端开发变得优雅而安全。
🏗️ 11.1.1 项目初始化与核心架构
# 快速创建项目
npm i -g @nestjs/cli
nest new my-ts-backend
核心项目结构:
src/
├── app.controller.ts # 控制器
├── app.module.ts # 根模块
├── app.service.ts # 服务
├── main.ts # 入口文件
└── users/ # 功能模块
├── users.controller.ts
├── users.service.ts
├── dto/ # 数据传输对象
└── entities/ # 实体类
🔧 11.1.2 类型安全的核心组件
数据传输对象(DTO)
// dto/create-user.dto.ts
export class CreateUserDto {
readonly name: string;
readonly email: string;
readonly password: string;
readonly age?: number;
}
实体类定义
// entities/user.entity.ts
export class User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
updatedAt: Date;
}
服务层实现
// users.service.ts
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { User } from './entities/user.entity';
@Injectable()
export class UsersService {
private readonly users: User[] = [];
private idCounter = 1;
/**
* 创建新用户
*/
create(createUserDto: CreateUserDto): User {
const newUser: User = {
id: this.idCounter++,
...createUserDto,
createdAt: new Date(),
updatedAt: new Date(),
};
this.users.push(newUser);
return newUser;
}
/**
* 获取所有用户
*/
findAll(): User[] {
return this.users;
}
/**
* 根据ID查找用户
*/
findOne(id: number): User | undefined {
return this.users.find(user => user.id === id);
}
}
控制器实现
// users.controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { User } from './entities/user.entity';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
/**
* 创建用户接口
*/
@Post()
create(@Body() createUserDto: CreateUserDto): User {
return this.usersService.create(createUserDto);
}
/**
* 获取用户列表接口
*/
@Get()
findAll(): User[] {
return this.usersService.findAll();
}
/**
* 获取单个用户接口
*/
@Get(':id')
findOne(@Param('id') id: string): User | undefined {
return this.usersService.findOne(+id);
}
}
🛡️ 11.1.3 中间件与验证管道
自定义验证管道
// pipes/validation.pipe.ts
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
import { ObjectSchema } from 'joi';
@Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(private schema: ObjectSchema) {}
/**
* 数据验证转换
*/
transform(value: any) {
const { error } = this.schema.validate(value);
if (error) {
throw new BadRequestException('验证失败');
}
return value;
}
}
日志中间件
// middleware/logger.middleware.ts
import { Request, Response, NextFunction } from 'express';
/**
* 请求日志中间件
*/
export function loggerMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
}
🗄️ 11.2 数据库操作的类型安全
🔗 11.2.1 TypeORM集成
实体定义
// entities/user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 100 })
name: string;
@Column({ unique: true })
email: string;
@Column({ select: false })
password: string;
@Column({ nullable: true })
age?: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
服务层数据操作
// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>
) {}
/**
* 创建用户
*/
async create(createUserDto: CreateUserDto): Promise<User> {
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
/**
* 查找所有用户
*/
async findAll(): Promise<User[]> {
return this.usersRepository.find();
}
/**
* 根据ID查找用户
*/
async findOne(id: number): Promise<User | undefined> {
return this.usersRepository.findOne({ where: { id } });
}
}
🎯 11.2.2 Prisma:端到端类型安全
Schema定义
// schema.prisma
model User {
id Int @id @default(autoincrement())
name String
email String @unique
password String
age Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
类型安全的数据操作
// users.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma.service';
import { User, Prisma } from '@prisma/client';
@Injectable()
export class UsersService {
constructor(private prisma: PrismaService) {}
/**
* 创建用户
*/
async create(data: Prisma.UserCreateInput): Promise<User> {
return this.prisma.user.create({ data });
}
/**
* 查找所有用户
*/
async findAll(): Promise<User[]> {
return this.prisma.user.findMany();
}
/**
* 查找单个用户
*/
async findOne(where: Prisma.UserWhereUniqueInput): Promise<User | null> {
return this.prisma.user.findUnique({ where });
}
}
🔒 11.2.3 高级类型技巧
安全返回类型
// 排除敏感字段的安全用户类型
export type SafeUser = Omit<User, 'password'>;
/**
* 转换为安全用户对象
*/
function toSafeUser(user: User): SafeUser {
const { password, ...safeData } = user;
return safeData;
}
部分更新DTO
// dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {
// 自动继承所有属性并设为可选
}
⚙️ 11.3 项目配置与部署
📝 11.3.1 TypeScript配置
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"strict": true,
"esModuleInterop": true,
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist", "test"]
}
🌍 11.3.2 环境配置
// config/configuration.ts
import { registerAs } from '@nestjs/config';
export default registerAs('app', () => ({
nodeEnv: process.env.NODE_ENV,
port: parseInt(process.env.PORT, 10) || 3000,
database: {
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT, 10) || 5432,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
name: process.env.DB_NAME,
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN,
},
}));
🐳 11.3.3 Docker部署
# Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main.js"]
📚 11.3.4 API文档集成
// main.ts
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
/**
* 应用启动函数
*/
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Swagger配置
const config = new DocumentBuilder()
.setTitle('用户管理API')
.setDescription('TypeScript后端API文档')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
🎯 本章核心收获
🚀 1. NestJS框架精通
- ✅ 类型安全架构:掌握了控制器、服务和模块的类型安全实现
- ✅ 依赖注入:学会了TypeScript装饰器与依赖注入的完美结合
- ✅ 中间件系统:实现了类型安全的请求处理管道
🗄️ 2. 数据库操作安全
- ✅ TypeORM集成:掌握了实体类与类型化仓库的使用
- ✅ Prisma优势:学会了端到端类型安全的数据操作
- ✅ 类型技巧:实现了安全返回类型与部分更新模式
⚙️ 3. 专业级配置
- ✅ 环境管理:建立了类型安全的配置系统
- ✅ 容器化部署:掌握了Docker多阶段构建
- ✅ API文档:集成了Swagger自动文档生成
💡 4. 开发最佳实践
- ✅ 代码组织:学会了模块化的项目结构设计
- ✅ 类型安全:实现了从数据库到API的完整类型保护
- ✅ 工程化思维:掌握了企业级后端应用的开发标准