TypeScript入门(十一)Node.js 后端开发:TypeScript的全栈力量

323 阅读4分钟

第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的完整类型保护
  • 工程化思维:掌握了企业级后端应用的开发标准