从入门到实战:TypeScript 全栈开发核心指南

大鹏人文

1. 为什么选择TypeScript全栈开发

第一次接触TypeScript是在2016年,当时团队正在重构一个大型电商后台系统。JavaScript的弱类型特性让我们在维护过程中吃尽了苦头——一个拼写错误可能要运行到特定分支才会暴露,接口数据结构变更时要在十几个文件中手动检查。自从切换到TypeScript后,这些痛点都得到了显著改善。

TypeScript作为JavaScript的超集,最核心的价值在于类型安全。想象你正在搭建乐高积木,TypeScript就像提供了形状匹配的凹槽,确保每个零件都能严丝合缝地拼接。这种特性在全栈开发中尤为重要,因为你需要同时处理:

  • 前端组件的数据流
  • 后端API的输入输出
  • 数据库模型定义
  • 跨层数据传输

我常用的技术栈组合是React+Express+TypeORM,这个组合的亮点在于端到端类型共享。比如定义一个用户类型后,可以在前端表单校验、API路由参数、数据库实体中复用,修改时只需调整一处。

2. 环境搭建与项目初始化

2.1 开发环境配置

新手常犯的错误是全局安装TypeScript,这可能导致不同项目版本冲突。推荐使用以下方式:

bash复制# 在项目目录中
npm init -y
npm install typescript --save-dev
npx tsc --init

生成的tsconfig.json需要重点关注这些配置项:

json复制{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

2.2 全栈项目结构设计

这是我经过多个项目验证的目录结构:

code复制project/
├── client/        # 前端代码
│   ├── src/
│   └── tsconfig.json
├── server/        # 后端代码
│   ├── src/
│   └── tsconfig.json
├── shared/        # 共享类型定义
│   └── types.ts
└── package.json

关键技巧是在根目录的package.json中添加workspaces配置:

json复制{
  "workspaces": [
    "client",
    "server",
    "shared"
  ]
}

这样可以通过import { User } from '@shared/types'实现跨项目类型共享。

3. 核心类型系统实战

3.1 接口与类型别名

接口(interface)和类型别名(type)看似相似,但在全栈开发中有明确分工:

typescript复制// 适合定义DTO和数据模型
interface User {
  id: number;
  name: string;
  email: string;
}

// 适合组合类型
type UserResponse = {
  data: User;
  meta: {
    page: number;
    total: number;
  };
};

实际项目中我会用接口定义数据库实体,用类型别名处理API响应格式。

3.2 泛型在API层的应用

这是我在实际项目中封装的API响应工具:

typescript复制// shared/api-types.ts
export interface ApiResponse<T = any> {
  code: number;
  data: T;
  message?: string;
}

// 使用示例
export function getUser(): Promise<ApiResponse<User>> {
  return axios.get('/api/user');
}

这种模式让前端能准确知道返回的数据结构,配合axios拦截器还能实现统一的错误处理。

4. 前后端类型共享方案

4.1 共享类型定义

在shared/types.ts中定义核心类型:

typescript复制export interface Product {
  id: string;
  name: string;
  price: number;
  inventory: number;
}

export type CartItem = {
  product: Product;
  quantity: number;
};

4.2 后端API实现

使用Express+TypeScript的典型路由:

typescript复制import { Request, Response } from 'express';
import { Product } from '@shared/types';

const products: Product[] = [...];

app.get('/api/products', (req: Request, res: Response<Product[]>) => {
  res.json(products);
});

app.post('/api/checkout', 
  (req: Request<{}, {}, CartItem[]>, res: Response<{ orderId: string }>) => {
    // 实现下单逻辑
  }
);

4.3 前端消费API

React组件中的类型安全请求:

typescript复制function ProductList() {
  const [products, setProducts] = useState<Product[]>([]);

  useEffect(() => {
    axios.get<Product[]>('/api/products')
      .then(res => setProducts(res.data));
  }, []);

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name} - ${p.price}</li>
      ))}
    </ul>
  );
}

5. 数据库集成与类型安全

5.1 TypeORM实体定义

typescript复制// server/src/entities/User.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column({ unique: true })
  email: string;
}

5.2 服务层类型转换

处理数据库实体与DTO的转换:

typescript复制// server/src/services/userService.ts
import { User } from '../entities/User';
import { CreateUserDto } from '../dtos';

export class UserService {
  async createUser(dto: CreateUserDto): Promise<User> {
    const user = new User();
    user.name = dto.name;
    user.email = dto.email;
    return await user.save();
  }
}

6. 高级类型技巧实战

6.1 类型守卫

处理联合类型时的类型收窄:

typescript复制function isAdmin(user: User | Admin): user is Admin {
  return 'permissions' in user;
}

function showDashboard(user: User | Admin) {
  if (isAdmin(user)) {
    // 这里user会被推断为Admin类型
    console.log(user.permissions);
  }
}

6.2 模板字面量类型

定义路由路径类型:

typescript复制type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';

type ApiRoute = `/api/${string}`;

function request(method: HttpMethod, url: ApiRoute) {
  // 实现请求逻辑
}

// 正确使用
request('GET', '/api/products');

// 类型错误
request('PATCH', '/products'); 

7. 项目构建与部署

7.1 构建配置优化

在tsconfig.json中添加这些生产环境配置:

json复制{
  "compilerOptions": {
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "sourceMap": false
  }
}

7.2 容器化部署

Dockerfile的TypeScript优化配置:

dockerfile复制FROM node:16

WORKDIR /app
COPY package*.json ./
COPY tsconfig.json ./

RUN npm install

COPY . .

RUN npm run build

CMD ["node", "dist/main.js"]

8. 常见问题解决方案

8.1 第三方库类型缺失

遇到没有类型定义的库时,可以这样处理:

  1. 尝试安装社区维护的类型包:
bash复制npm install --save-dev @types/库名
  1. 对于没有类型的库,可以创建声明文件:
typescript复制// src/types/module.d.ts
declare module 'untyped-module' {
  export function someFunction(arg: string): void;
}

8.2 类型声明合并

扩展第三方库的类型定义:

typescript复制// 扩展Express的Request类型
declare global {
  namespace Express {
    interface Request {
      user?: {
        id: string;
        role: string;
      };
    }
  }
}

9. 性能优化实践

9.1 增量编译

启用tsconfig.json中的增量编译:

json复制{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo"
  }
}

9.2 项目引用

对于大型项目,使用项目引用拆分代码:

json复制// tsconfig.base.json
{
  "compilerOptions": {
    "composite": true
  },
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" }
  ]
}

10. 测试策略

10.1 单元测试类型检查

使用Jest时确保测试代码也通过类型检查:

typescript复制// __tests__/userService.test.ts
import { UserService } from '../services/userService';

describe('UserService', () => {
  let service: UserService;

  beforeEach(() => {
    service = new UserService();
  });

  test('createUser should return user with id', async () => {
    const user = await service.createUser({
      name: 'Test',
      email: 'test@example.com'
    });
    expect(user.id).toBeDefined();
  });
});

10.2 接口契约测试

使用类型安全的API测试:

typescript复制import { ApiResponse } from '@shared/types';

test('GET /api/products returns valid structure', async () => {
  const res = await request(app)
    .get('/api/products');
  
  const data: ApiResponse<Product[]> = res.body;
  
  expect(data.code).toBe(200);
  expect(Array.isArray(data.data)).toBe(true);
});

11. 项目重构技巧

11.1 渐进式迁移

将JavaScript项目逐步迁移到TypeScript:

  1. 重命名.js文件为.ts
  2. 逐步添加类型注解
  3. 配置allowJs选项
  4. 开启严格模式分阶段

11.2 类型提取策略

发现重复类型定义时:

typescript复制// 重构前
function getUser(): Promise<{ id: string; name: string }> {...}
function updateUser(user: { id: string; name: string }) {...}

// 重构后
type UserBasic = {
  id: string;
  name: string;
};

function getUser(): Promise<UserBasic> {...}
function updateUser(user: UserBasic) {...}

12. 调试技巧

12.1 源映射配置

确保调试时能定位到源码:

json复制{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSources": true
  }
}

12.2 类型调试技巧

使用类型推导检查复杂类型:

typescript复制type ComplexType = ...;

// 鼠标悬停在DebugType上查看实际类型
type DebugType = ComplexType extends infer T ? T : never;

13. 团队协作规范

13.1 代码风格统一

推荐配置:

json复制{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedParameters": true
  }
}

13.2 代码审查要点

审查TypeScript代码时重点关注:

  1. 是否滥用any类型
  2. 接口定义是否合理
  3. 类型复用程度
  4. 复杂类型的可读性
  5. 类型守卫使用是否恰当

14. 前端框架集成

14.1 React组件类型

定义带类型的函数组件:

typescript复制interface Props {
  title: string;
  count: number;
  onIncrement?: () => void;
}

const Counter: React.FC<Props> = ({ title, count, onIncrement }) => {
  return (
    <div>
      <h2>{title}</h2>
      <span>{count}</span>
      {onIncrement && <button onClick={onIncrement}>+</button>}
    </div>
  );
};

14.2 Vue组合式API

使用TypeScript的setup语法:

typescript复制<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const count = ref(0); // 自动推断为Ref<number>

    function increment() {
      count.value++;
    }

    return { count, increment };
  }
});
</script>

15. 后端框架深度集成

15.1 NestJS类型系统

利用装饰器实现类型安全:

typescript复制@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get(':id')
  async findOne(@Param('id') id: string): Promise<User> {
    return this.usersService.findOne(+id);
  }
}

15.2 Express中间件类型

自定义中间件类型:

typescript复制import { RequestHandler } from 'express';

interface AuthRequest extends Request {
  user: {
    id: string;
    role: string;
  };
}

export const authMiddleware: RequestHandler<{}, any, any, {}, AuthRequest> = 
  (req, res, next) => {
    // 实现认证逻辑
    req.user = { id: '123', role: 'admin' };
    next();
  };

16. 数据库高级技巧

16.1 复杂查询类型

使用TypeORM的QueryBuilder保持类型安全:

typescript复制const users = await userRepository
  .createQueryBuilder('user')
  .leftJoinAndSelect('user.posts', 'post')
  .where('user.age > :age', { age: 18 })
  .orderBy('user.name', 'ASC')
  .getMany(); // 返回类型为User[]

16.2 事务处理模式

类型安全的事务封装:

typescript复制async function runInTransaction<T>(
  work: (manager: EntityManager) => Promise<T>
): Promise<T> {
  return getManager().transaction(async manager => {
    return await work(manager);
  });
}

// 使用示例
await runInTransaction(async manager => {
  const user = manager.create(User, { name: 'New' });
  await manager.save(user);
  return user;
});

17. 微服务架构应用

17.1 gRPC接口定义

使用protobuf生成类型:

proto复制syntax = "proto3";

service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
}

message UserRequest {
  string id = 1;
}

message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
}

17.2 消息队列类型

定义RabbitMQ消息类型:

typescript复制interface OrderMessage {
  orderId: string;
  userId: string;
  items: Array<{
    productId: string;
    quantity: number;
  }>;
}

channel.consume('orders', (msg) => {
  if (msg) {
    const content: OrderMessage = JSON.parse(msg.content.toString());
    // 处理消息
  }
});

18. 前端状态管理

18.1 Redux Toolkit类型

创建类型安全的store:

typescript复制import { configureStore } from '@reduxjs/toolkit';

const store = configureStore({
  reducer: {
    users: usersReducer,
    posts: postsReducer
  }
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

18.2 React Context模式

类型安全的Context实现:

typescript复制interface AuthContextType {
  user: User | null;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

const AuthContext = React.createContext<AuthContextType | null>(null);

function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth必须在AuthProvider内使用');
  }
  return context;
}

19. 性能监控集成

19.1 类型化监控指标

定义性能指标类型:

typescript复制interface PerformanceMetrics {
  pageLoad: number;
  apiResponseTimes: Record<string, number>;
  memoryUsage: {
    jsHeapSizeLimit: number;
    totalJSHeapSize: number;
    usedJSHeapSize: number;
  };
}

function sendMetrics(metrics: PerformanceMetrics) {
  // 发送到监控系统
}

19.2 错误跟踪集成

类型安全的错误处理:

typescript复制interface TrackedError extends Error {
  code?: string;
  context?: Record<string, unknown>;
  isOperational?: boolean;
}

function trackError(error: TrackedError) {
  // 错误上报逻辑
}

20. 持续集成流程

20.1 类型检查流水线

在CI中添加类型检查步骤:

yaml复制steps:
  - name: Install dependencies
    run: npm ci
  
  - name: Type check
    run: npx tsc --noEmit
  
  - name: Run tests
    run: npm test

20.2 依赖版本检查

使用类型安全的版本检查:

typescript复制interface DependencyCheck {
  name: string;
  current: string;
  latest: string;
  isOutdated: boolean;
}

function checkDependencies(): Promise<DependencyCheck[]> {
  // 实现检查逻辑
}

21. 文档生成策略

21.1 TypeDoc集成

自动生成API文档:

bash复制npm install --save-dev typedoc
npx typedoc --out docs src/index.ts

21.2 示例代码验证

确保文档中的代码示例通过类型检查:

typescript复制// 在测试文件中验证示例
test('文档示例1', () => {
  const example = () => {
    // 从文档复制的示例代码
    interface Point {
      x: number;
      y: number;
    }
    const p: Point = { x: 10, y: 20 };
    return p;
  };
  
  expect(example()).toEqual({ x: 10, y: 20 });
});

22. 安全最佳实践

22.1 输入验证类型

定义安全的输入类型:

typescript复制type SanitizedString = string & { __brand: 'Sanitized' };

function sanitize(input: string): SanitizedString {
  // 实现清理逻辑
  return input.replace(/<script.*?>.*?<\/script>/gi, '') as SanitizedString;
}

function saveContent(content: SanitizedString) {
  // 安全地保存内容
}

22.2 权限检查类型

类型安全的权限系统:

typescript复制type Permission = 'read' | 'write' | 'delete';

interface UserWithPermissions {
  id: string;
  permissions: Permission[];
}

function checkPermission(
  user: UserWithPermissions,
  required: Permission
): boolean {
  return user.permissions.includes(required);
}

23. 国际化方案

23.1 类型化翻译系统

定义翻译键类型:

typescript复制type TranslationKey = 
  | 'home.title'
  | 'home.subtitle'
  | 'button.submit'
  | 'button.cancel';

const translations: Record<TranslationKey, string> = {
  'home.title': 'Welcome',
  'home.subtitle': 'Enjoy your stay',
  'button.submit': 'Submit',
  'button.cancel': 'Cancel'
};

function t(key: TranslationKey): string {
  return translations[key];
}

23.2 多语言资源类型

类型安全的语言包:

typescript复制interface LocaleResources {
  common: {
    buttons: {
      ok: string;
      cancel: string;
    };
  };
  pages: {
    home: {
      title: string;
    };
  };
}

const en: LocaleResources = {
  common: {
    buttons: {
      ok: 'OK',
      cancel: 'Cancel'
    }
  },
  pages: {
    home: {
      title: 'Home'
    }
  }
};

24. 可视化图表集成

24.1 图表数据类型

定义类型化的图表配置:

typescript复制interface ChartData<T = number | string> {
  labels: string[];
  datasets: Array<{
    label: string;
    data: T[];
    backgroundColor?: string | string[];
  }>;
}

function renderBarChart(data: ChartData<number>) {
  // 渲染柱状图
}

function renderPieChart(data: ChartData<string>) {
  // 渲染饼图
}

24.2 仪表盘组件

类型安全的仪表盘组件:

typescript复制interface DashboardProps {
  widgets: Array<{
    id: string;
    type: 'chart' | 'metric' | 'table';
    title: string;
    data: unknown; // 具体类型根据widget类型确定
  }>;
  layout: {
    columns: number;
    rowHeight: number;
  };
}

function Dashboard({ widgets, layout }: DashboardProps) {
  // 实现仪表盘渲染
}

25. 移动端适配方案

25.1 响应式类型

定义响应式断点类型:

typescript复制type Breakpoint = 'mobile' | 'tablet' | 'desktop';

function useBreakpoint(): Breakpoint {
  // 实现断点检测逻辑
  return 'desktop';
}

function ResponsiveComponent() {
  const bp = useBreakpoint();
  
  return (
    <div>
      {bp === 'mobile' && <MobileView />}
      {bp === 'tablet' && <TableView />}
      {bp === 'desktop' && <DesktopView />}
    </div>
  );
}

25.2 平台特定代码

类型安全的平台检测:

typescript复制type Platform = 'ios' | 'android' | 'web';

function getPlatform(): Platform {
  // 实现平台检测
  return 'web';
}

const platformComponents: Record<Platform, React.ComponentType> = {
  ios: IOSComponent,
  android: AndroidComponent,
  web: WebComponent
};

function PlatformComponent() {
  const CurrentComponent = platformComponents[getPlatform()];
  return <CurrentComponent />;
}

26. Web组件开发

26.1 自定义元素类型

定义类型安全的Web组件:

typescript复制declare global {
  namespace JSX {
    interface IntrinsicElements {
      'my-component': {
        'count'?: number;
        'onIncrement'?: (e: CustomEvent) => void;
      };
    }
  }
}

// 使用
<my-component 
  count={5} 
  onIncrement={(e) => console.log(e.detail)} 
/>

26.2 Shadow DOM集成

类型化的Shadow DOM操作:

typescript复制interface ShadowRootWithStyles extends ShadowRoot {
  adoptedStyleSheets: CSSStyleSheet[];
}

function createComponent(): HTMLElement {
  const element = document.createElement('div');
  const shadow = element.attachShadow({ mode: 'open' }) as ShadowRootWithStyles;
  
  const sheet = new CSSStyleSheet();
  sheet.replaceSync(':host { display: block; }');
  shadow.adoptedStyleSheets = [sheet];
  
  return element;
}

27. 浏览器API封装

27.1 类型化LocalStorage

安全的存储封装:

typescript复制type StorageKey = 'userToken' | 'darkMode' | 'lastVisited';

function getStorageItem<T>(key: StorageKey): T | null {
  const item = localStorage.getItem(key);
  return item ? JSON.parse(item) : null;
}

function setStorageItem<T>(key: StorageKey, value: T): void {
  localStorage.setItem(key, JSON.stringify(value));
}

// 使用
const token = getStorageItem<string>('userToken');
setStorageItem('darkMode', true);

27.2 Fetch API封装

类型安全的HTTP客户端:

typescript复制async function fetchJson<T = unknown>(
  input: RequestInfo,
  init?: RequestInit
): Promise<T> {
  const response = await fetch(input, init);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  return response.json() as Promise<T>;
}

// 使用
interface User {
  id: string;
  name: string;
}

const user = await fetchJson<User>('/api/user/123');

28. Node.js工具开发

28.1 CLI工具类型

类型安全的命令行工具:

typescript复制import { Command } from 'commander';

interface CliOptions {
  config?: string;
  verbose?: boolean;
  output?: string;
}

const program = new Command();

program
  .option('-c, --config <path>', 'config file path')
  .option('-v, --verbose', 'verbose output')
  .option('-o, --output <dir>', 'output directory');

program.parse(process.argv);

const options = program.opts() as CliOptions;

if (options.verbose) {
  console.log('Running in verbose mode');
}

28.2 文件系统操作

类型化的文件操作:

typescript复制interface FileStats {
  path: string;
  size: number;
  modified: Date;
  isDirectory: boolean;
}

async function getFileStats(path: string): Promise<FileStats> {
  const stats = await fs.promises.stat(path);
  return {
    path,
    size: stats.size,
    modified: stats.mtime,
    isDirectory: stats.isDirectory()
  };
}

29. 算法与数据结构

29.1 类型安全的链表

实现泛型链表:

typescript复制class ListNode<T> {
  constructor(
    public value: T,
    public next: ListNode<T> | null = null
  ) {}
}

class LinkedList<T> {
  private head: ListNode<T> | null = null;

  append(value: T): void {
    const newNode = new ListNode(value);
    if (!this.head) {
      this.head = newNode;
      return;
    }
    
    let current = this.head;
    while (current.next) {
      current = current.next;
    }
    current.next = newNode;
  }

  // 其他方法...
}

29.2 排序算法泛型

泛型快速排序实现:

typescript复制function quickSort<T>(arr: T[], compare: (a: T, b: T) => number): T[] {
  if (arr.length <= 1) return arr;
  
  const pivot = arr[0];
  const left: T[] = [];
  const right: T[] = [];
  
  for (let i = 1; i < arr.length; i++) {
    if (compare(arr[i], pivot) < 0) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  
  return [...quickSort(left, compare), pivot, ...quickSort(right, compare)];
}

// 使用
const numbers = [5, 3, 8, 1, 2];
const sorted = quickSort(numbers, (a, b) => a - b);

30. 图形编程应用

30.1 Canvas类型操作

类型安全的Canvas绘图:

typescript复制function drawCircle(
  ctx: CanvasRenderingContext2D,
  x: number,
  y: number,
  radius: number,
  color: string
): void {
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI * 2);
  ctx.fillStyle = color;
  ctx.fill();
}

const canvas = document.getElementById('canvas') as HTMLCanvasElement;
const ctx = canvas.getContext('2d');
if (ctx) {
  drawCircle(ctx, 100, 100, 50, '#ff0000');
}

30.2 WebGL类型封装

类型化的WebGL程序:

typescript复制interface ShaderProgram {
  program: WebGLProgram;
  attributes: Record<string, number>;
  uniforms: Record<string, WebGLUniformLocation | null>;
}

function createShaderProgram(
  gl: WebGLRenderingContext,
  vertexShaderSource: string,
  fragmentShaderSource: string
): ShaderProgram {
  // 实现着色器程序创建
  return {
    program,
    attributes: {},
    uniforms: {}
  };
}

31. 测试工具开发

31.1 类型化测试数据

生成类型安全的测试数据:

typescript复制interface TestUser {
  id: string;
  name: string;
  email: string;
  age: number;
}

function createTestUser(overrides?: Partial<TestUser>): TestUser {
  return {
    id: 'user_' + Math.random().toString(36).substr(2, 9),
    name: 'Test User',
    email: 'test@example.com',
    age: 25,
    ...overrides
  };
}

// 使用
const adminUser = createTestUser({ name: 'Admin', age: 30 });

31.2 测试断言封装

类型安全的断言库:

typescript复制interface Assert {
  <T>(actual: T, expected: T, message?: string): void;
  deepEqual<T>(actual: T, expected: T, message?: string): void;
  throws(fn: () => void, error?: Error | string | RegExp): void;
}

const assert: Assert = {
  <T>(actual: T, expected: T, message?: string) {
    if (actual !== expected) {
      throw new Error(message || `Expected ${expected}, got ${actual}`);
    }
  },
  deepEqual<T>(actual: T, expected: T, message?: string) {
    if (JSON.stringify(actual) !== JSON.stringify(expected)) {
      throw new Error(message || 'Deep equality check failed');
    }
  },
  throws(fn, error) {
    let threw = false;
    try {
      fn();
    } catch (e) {
      threw = true;
      if (error) {
        if (typeof error === 'string') {
          if (e.message !== error) {
            throw new Error(`Expected error message "${error}", got "${e.message}"`);
          }
        } else if (error instanceof RegExp) {
          if (!error.test(e.message)) {
            throw new Error(`Expected error message to match ${error}, got "${e.message}"`);
          }
        } else if (e instanceof error.constructor) {
          if (e.message !== error.message) {
            throw new Error(`Expected error "${error.message}", got "${e.message}"`);
          }
        }
      }
    }
    if (!threw) {
      throw new Error('Expected function to throw');
    }
  }
};

32. 实用工具类型

32.1 深度只读类型

实现深度只读类型:

typescript复制type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

interface User {
  name: string;
  profile: {
    age: number;
    address: string;
  };
}

const user: DeepReadonly<User> = {
  name: 'Alice',
  profile: {
    age: 25,
    address: '123 Main St'
  }
};

// 以下代码会报错
// user.name = 'Bob';
// user.profile.age = 30;

32.2 条件类型工具

实用的条件类型:

typescript复制type Nullable<T> = T | null;
type Maybe<T> = T | undefined;
type ValueOf<T> = T[keyof T];
type Promisify<T> = T extends Promise<infer U> ? T : Promise<T>;

// 使用示例
type User = { name: string; age: number };
type UserValue = ValueOf<User>; // string | number

33. 设计模式实现

33.1 工厂模式

类型安全的工厂函数:

typescript复制interface Product {
  name: string;
  price: number;
  description(): string;
}

class Book implements Product {
  constructor(
    public name: string,
    public price: number,
    public author: string
  ) {}

  description(): string {
    return `${this.name} by ${this.author}`;
  }
}

class Electronics implements Product {
  constructor(
    public name: string,
    public price: number,
    public brand: string
  ) {}

  description(): string {
    return `${this.brand} ${this.name}`;
  }
}

function createProduct<T extends Product>(
  type: new (...args: any[]) => T,
  ...args: ConstructorParameters<typeof type>
): T {
  return new type(...args);
}

// 使用
const book = createProduct(Book, 'TypeScript Guide', 29.99, 'John Doe');
const laptop = createProduct(Electronics, 'Laptop', 999.99, 'Apple');

33.2 观察者模式

类型安全的事件系统:

typescript复制type Listener<T> = (event: T) => void;

class EventEmitter<T> {
  private listeners: Listener<T>[] = [];

  addListener(listener: Listener<T>): void {
    this.listeners.push(listener);
  }

  removeListener(listener: Listener<T>): void {
    this.listeners = this.listeners.filter(l => l !== listener);
  }

  emit(event: T): void {
    for (const listener of this.listeners) {
      listener(event);
    }
  }
}

// 使用
interface UserEvent {
  userId: string;
  action: 'login' | 'logout';
}

const userEvents = new EventEmitter<UserEvent>();
userEvents.addListener(event => {
  console.log(`User ${event.userId} ${event.action}`);
});

userEvents.emit({ userId: '123', action: 'login' });

34. 函数式编程

34.1 柯里化函数

类型安全的柯里化:

typescript复制function curry<T1, T2, R>(fn: (a: T1, b: T2) => R): (a: T1) => (b: T2) => R;
function curry<T1, T2, T3, R>(fn: (a: T1, b: T2, c: T3) => R): (a: T1) => (b: T2) => (c: T3) => R;
function curry(fn: (...args: any[]) => any): (...args: any[]) => any {
  return function curried(...args: any[]) {
    if (args.length >= fn.length) {
      return fn(...args);
    } else {
      return (...moreArgs: any[]) => curried(...args, ...moreArgs);
    }
  };
}

// 使用
const add = (a: number, b: number) => a + b;
const curriedAdd = curry(add);
const addFive = curriedAdd(5);
console.log(addFive(3)); // 8

34.2 函数组合

类型安全的函数组合:

typescript复制function compose<T1, T2, T3>(
  f: (x: T2) => T3,
  g: (x: T1) => T2
): (x: T1) => T3 {
  return (x) => f(g(x));
}

// 使用
const toUpperCase = (s: string) => s.toUpperCase();
const exclaim = (s: string) => s + '!';
const shout = compose(exclaim, toUpperCase);

console.log(shout('hello')); // "HELLO!"

35. 并发编程

35.1 类型化Worker

安全地与Web Worker通信:

typescript复制// worker.ts
interface WorkerMessage<T = any> {
  type: string;
  payload: T;
}

self.onmessage = (e: MessageEvent<WorkerMessage>) => {
  if (e.data.type === 'CALCULATE') {
    const result = doCalculation(e.data.payload);
    self.postMessage({
      type: 'RESULT',
      payload: result
    });
  }
};

function doCalculation(input: number): number {
  return input * 2;
}

// main.ts
const worker

内容推荐

SIGGRAPH 2026投稿指南:手把手教你用LaTeX搞定ACM双栏格式(附模板下载)
本文详细介绍了SIGGRAPH 2026投稿的LaTeX排版指南,重点解析ACM双栏格式的使用技巧。作为CCF推荐的A类会议,SIGGRAPH在计算机图形学领域具有重要影响力。文章从模板下载、环境配置到最终PDF生成,提供了一套完整的解决方案,帮助研究者高效完成论文排版,避免常见格式错误。
OpenCV棋盘格检测翻车实录:findChessboardCornersSB的5个隐藏坑与调参秘籍
本文深入剖析了OpenCV中findChessboardCornersSB函数在棋盘格检测中的5个常见问题与调参技巧。从低对比度图像处理到极端透视畸变应对,再到部分遮挡容错和flag组合优化,提供了实战验证的解决方案。特别针对工业视觉场景,分享了多尺度检测的性能优化策略,帮助开发者提升检测成功率和效率。
ArcGIS面积统计翻车现场:双精度字段没设对?投影坐标系选错了?5分钟排雷指南
本文针对ArcGIS面积统计中常见的双精度字段设置错误和投影坐标系选择问题,提供了详细的5分钟排雷指南。通过分析字段类型陷阱和坐标系迷阵,结合GlobalMapper的闪电定位技巧,帮助用户快速解决面积计算失真的问题,提升GIS数据处理效率。
GNU Radio Embedded Python Block避坑指南:从编辑器配置到向量信号处理的完整流程
本文详细解析了GNU Radio中Embedded Python Block的开发流程,从编辑器配置到信号处理优化,涵盖了环境一致性检查、模块架构设计、NumPy向量化操作等关键技巧。特别针对复数信号处理和自定义模块开发中的常见问题提供了实用解决方案,帮助开发者高效构建高性能信号处理应用。
从Photoshop到VS Code:聊聊QMdiArea如何塑造我们熟悉的桌面软件界面
本文探讨了QMdiArea在桌面软件界面设计中的关键作用,从Photoshop到VS Code的经典案例出发,详细解析了Qt框架中QMdiArea控件的实现技巧与现代MDI的混合式实践。通过代码示例和性能优化方案,帮助开发者掌握如何利用QMdiArea构建高效、灵活的多文档界面,提升用户体验。
别再死记硬背Redis数据结构了!用Spring Boot实战5个真实业务场景(附完整代码)
本文通过Spring Boot实战演示Redis数据结构在5大真实业务场景中的应用,包括分布式Session共享、购物车系统、订单日志处理、社交关系分析和排行榜系统。文章提供完整代码示例,帮助开发者摆脱死记硬背,掌握Redis在分布式系统中的高效应用技巧,提升系统性能与开发效率。
量化小白也能懂:用Tushare+Python分析A股概念板块的季节性规律(实战案例)
本文介绍如何利用Tushare和Python分析A股概念板块的季节性规律,适合量化投资新手入门。通过获取历史概念板块数据,计算平均涨跌幅,验证春节效应等季节性现象,并提供可视化分析和策略建议,帮助读者挖掘A股市场的周期性机会。
基于Electron与STM32的嵌入式设备批量序列号烧录工具开发实战
本文详细介绍了基于Electron与STM32的嵌入式设备批量序列号烧录工具开发实战。通过Electron框架实现跨平台上位机开发,结合STM32的IAP编程技术,显著提升产线烧录效率与稳定性。文章涵盖串口通信优化、固件设计、数据库集成等关键技术,并分享性能优化经验,助力工业自动化生产。
保姆级教程:在Windows Server用Oracle 19c建库并搞定远程访问(含sqlnet.ora/listener.ora配置详解)
本文提供Windows Server环境下Oracle 19c数据库的完整部署指南,涵盖安装过程、远程访问配置及常见问题解决(如ORA-28040错误)。详细解析sqlnet.ora和listener.ora文件配置,帮助IT人员快速搭建高效、安全的企业级数据库系统。
从设计到筛选:CRISPR/Cas9基因编辑实验全流程实战解析
本文详细解析了CRISPR/Cas9基因编辑实验的全流程,从sgRNA设计、载体构建到细胞转染与抗性筛选,再到阳性克隆鉴定与数据分析。通过实战经验和技巧分享,帮助科研人员高效完成基因编辑实验,提升实验成功率并优化时间与成本控制。
【C/C++】从零实现康威生命游戏:核心算法与内存管理实战
本文详细介绍了如何使用C/C++从零实现康威生命游戏,涵盖核心算法、动态内存管理和性能优化。通过模块化设计、双缓冲技术和边界处理技巧,开发者可以高效实现这一经典细胞自动机,并深入理解内存管理和算法优化。文章还提供了扩展功能建议和常见问题排查方法,适合C/C++开发者提升编程技能。
别再乱用wx.login了!手把手教你用checkSession搞定小程序登录态失效
本文深入解析微信小程序登录态管理机制,重点介绍如何正确使用`wx.checkSession`避免登录态失效问题。通过对比错误实践与最佳方案,提供完整的登录态管理架构设计,帮助开发者从根源解决授权失败问题,显著提升小程序稳定性与用户体验。
【前沿 热点 顶会】AAAI 2025:目标检测新范式——从通用检测到跨模态融合
AAAI 2025展示了目标检测领域的最新突破,从通用检测到跨模态融合。CP-DETR通过概念提示技术实现零样本检测,SCKD方案利用半监督知识蒸馏提升雷达检测性能,而RCTrans则通过Transformer架构优化3D场景还原。这些创新技术为自动驾驶、工业质检等场景带来显著性能提升。
科研绘图实战指南【26】论文图表优化技巧(持续更新)
本文详细介绍了科研论文图表优化的实战技巧,涵盖Excel数据可视化进阶、学术级流程图绘制、多维数据展示等关键方法。通过具体案例和工具推荐,帮助研究者提升图表质量,满足审稿人的专业要求,显著提高论文接受率。特别强调图表设计的信息准确性和视觉规范性,是科研绘图的必备指南。
自恢复保险丝防反接方案全测评:从选型到发热处理(PPTC实战指南)
本文全面测评自恢复保险丝(PPTC)在电源反接保护电路中的应用,从核心原理、电路设计到选型参数和发热处理,提供实战指南。重点对比不同电流规格PPTC的性能,分析工业级选型要点,并介绍PPTC与MOS管的混合设计方案,帮助工程师优化防反接保护系统。
保姆级教程:用RK3588+ZYNQ7045给机器人装个‘超强大脑’(含国产FPGA选型指南)
本文详细介绍了如何利用RK3588和ZYNQ7045构建机器人智能中枢,实现ARM+FPGA+NPU的异构架构设计。通过硬件搭建、软件开发环境配置及典型应用案例,帮助开发者解决实时性、能效比和扩展性等核心问题,特别提供国产FPGA选型与适配指南。
从硬件到驱动:手把手教你为泰山派扩展板适配3.1寸MIPI屏(含GP7101背光驱动详解)
本文详细介绍了为泰山派开发板适配3.1寸MIPI屏幕的全过程,包括硬件电路设计、Linux设备树配置和GP7101背光驱动开发。特别针对MIPI接口信号分析和背光驱动电路设计提供了实用解决方案,帮助开发者快速实现屏幕驱动适配。
从MAAB规范到团队标准:如何用Model Advisor自定义检查打造你的Simulink建模‘门禁系统’
本文探讨如何基于Model Advisor构建企业级Simulink建模质量门禁系统,涵盖从MAAB规范到团队自定义检查的三层体系设计。通过Matlab编程技巧实现硬件约束检查、建模模式约束等定制规则,并分享与CI/CD流水线集成的工程化方案,帮助团队提升模型质量与合规性。
echarts map3D散点点击失效的排查与解决方案
本文详细分析了ECharts中map3D散点点击失效的问题,提供了四种有效的解决方案,包括合并散点数据、添加虚拟数据点、自定义渲染逻辑和降级使用2D模式。文章还分享了最佳实践、性能优化技巧和调试方法,帮助开发者快速解决类似问题。
【MISC】集对分析法 (SPA) 与熵权法的融合:优化复杂决策的新路径
本文探讨了集对分析法(SPA)与熵权法的融合应用,为复杂决策提供优化路径。通过详细步骤和真实案例分析,展示了如何量化模糊关系并客观分配指标权重,提升决策的科学性和准确性。智慧农业项目的实践验证了该方法在平衡技术、成本和社会因素方面的有效性。
已经到底了哦
精选内容
热门内容
最新内容
Qwen2指令微调实战:从零构建文本分类模型(附完整代码)
本文详细介绍了如何使用Qwen2大模型进行指令微调,从零构建文本分类模型。通过环境配置、数据处理、LoRA参数调优到模型推理部署的全流程实战,帮助开发者掌握高效微调技术,提升模型在中文文本分类任务中的表现。附完整代码实现,适合AI开发者快速上手。
别再死记硬背命令了!用eNSP模拟华为防火墙双机热备,我带你一步步理解VGMP和HRP协议
本文通过eNSP模拟华为防火墙双机热备环境,深入解析VGMP和HRP协议的工作原理。从抓包分析到实战配置,详细讲解如何避免传统VRRP的不足,确保防火墙会话表和安全策略的同步,提升网络高可用性。适合网络工程师和华为防火墙用户学习双机热备技术。
告别LM2596!智能车舵机供电实测:AS1015方案如何让38KG舵机不‘掉链子’
本文深度评测了智能车舵机供电方案,重点对比了传统LM2596与新型AS1015在38KG大力舵机上的表现。AS1015凭借P-MOSFET架构和同步整流技术,显著降低电压骤降和纹波,提升响应速度和稳定性,为智能车竞赛提供更可靠的硬件设计解决方案。
嵌入式GUI LVGL『Spinbox微调器控件』实战:从配置到事件处理的完整指南
本文详细介绍了嵌入式GUI开发中LVGL的Spinbox微调器控件的实战应用,从基础配置到高级事件处理。通过智能家居温控面板的实例,展示了如何设置数值范围、步长调整以及自定义按钮样式,帮助开发者高效实现精确数值输入的交互功能。
跨越平台障碍:Python-PCL在Windows与Linux下的实战安装与避坑指南
本文详细解析了Python-PCL在Windows与Linux系统下的安装与配置技巧,重点解决跨平台环境中的常见问题。通过实战案例展示如何规避DLL加载失败、依赖库冲突等典型错误,提供点云处理工具的高效部署方案,帮助开发者快速搭建稳定的点云处理环境。
从原理到实战:手把手教你用VMware虚拟机安全玩转WinPE工具箱(含UEFI/BIOS切换指南)
本文详细介绍了如何在VMware虚拟机中安全使用WinPE工具箱进行系统维护,包括UEFI/BIOS切换、USB设备连接等实用技巧。通过虚拟化环境,用户可以零风险练习密码重置、分区调整等操作,同时掌握系统备份与数据恢复的最佳实践。
龙迅LT8712SX:解锁双屏扩展新体验,Type-C/DP1.4转双路输出的MST与SST实战解析
本文深入解析龙迅LT8712SX芯片如何通过Type-C/DP1.4接口实现双屏扩展,支持MST多流传输技术,满足4K@60Hz双屏异显需求。详细介绍了其核心技术特性、MST与SST模式对比及典型应用方案设计,为专业办公和内容创作提供高效解决方案。
伺服电机选型实战:从功率计算到惯量匹配的工程决策
本文深入探讨伺服电机选型的工程实践,从功率计算到惯量匹配,提供系统化的选型方法论。通过负载特性分析、运动曲线建模和热损耗验证等步骤,帮助工程师避免常见陷阱,优化动态响应特性。文章特别强调惯量匹配的重要性,并分享实战技巧和品牌参数对比,助力精准选型。
从腾讯会议用OV、钉钉用EV说起:聊聊企业选SSL证书的那些‘潜规则’与成本考量
本文深入探讨企业SSL证书选型策略,从腾讯会议使用的OV证书到钉钉采用的EV证书,分析DV、OV、EV三级证书的商业逻辑与成本差异。通过头部产品案例和四维决策模型,帮助企业根据业务风险、用户认知、预算和技术兼容性选择最优方案,提升安全性与用户信任。
告别“没有注册类”:从原理到实战,一站式解决MSComm控件注册难题
本文详细解析了MSComm控件注册失败的常见原因及解决方案,包括文件位置、权限不足和注册表密钥缺失等问题。通过批处理脚本和注册表操作指南,帮助开发者一站式解决“没有注册类”错误,提升开发效率。