BlockCoder
后端开发··12 分钟

TypeScript 最佳实践:写出更安全的代码

掌握 TypeScript 的核心概念和最佳实践,学会使用类型系统来提升代码质量和开发效率。

#TypeScript#JavaScript#类型安全#最佳实践

TypeScript 为 JavaScript 带来了静态类型检查,让我们能够在编译时发现错误,提升代码的可维护性和可靠性。

🎯 基础类型使用

基本类型定义

typescript
1// 基础类型
2const name: string = "张三";
3const age: number = 25;
4const isActive: boolean = true;
5
6// 数组类型
7const numbers: number[] = [1, 2, 3];
8const names: Array<string> = ["Alice", "Bob"];
9
10// 对象类型
11interface User {
12  id: number;
13  name: string;
14  email?: string; // 可选属性
15  readonly createdAt: Date; // 只读属性
16}

联合类型和交叉类型

typescript
1// 联合类型
2type Status = "pending" | "approved" | "rejected";
3type ID = string | number;
4
5// 交叉类型
6interface Timestamped {
7  createdAt: Date;
8  updatedAt: Date;
9}
10
11type UserWithTimestamp = User & Timestamped;

🔧 高级类型技巧

泛型的使用

typescript
1// 泛型函数
2function identity<T>(arg: T): T {
3  return arg;
4}
5
6// 泛型接口
7interface ApiResponse<T> {
8  data: T;
9  status: number;
10  message: string;
11}
12
13// 泛型约束
14interface Lengthwise {
15  length: number;
16}
17
18function loggingIdentity<T extends Lengthwise>(arg: T): T {
19  console.log(arg.length);
20  return arg;
21}

实用工具类型

typescript
1interface User {
2  id: number;
3  name: string;
4  email: string;
5  password: string;
6}
7
8// Partial - 使所有属性可选
9type PartialUser = Partial<User>;
10
11// Pick - 选择特定属性
12type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
13
14// Omit - 排除特定属性
15type CreateUser = Omit<User, 'id'>;
16
17// Required - 使所有属性必需
18type RequiredUser = Required<PartialUser>;

📝 最佳实践

1. 严格的类型检查

json
1// tsconfig.json
2{
3  "compilerOptions": {
4    "strict": true,
5    "noImplicitAny": true,
6    "strictNullChecks": true,
7    "strictFunctionTypes": true
8  }
9}

2. 使用类型断言谨慎

typescript
1// ❌ 避免使用 any
2const data: any = response.data;
3
4// ❌ 过度使用类型断言
5const user = data as User;
6
7// ✅ 使用类型守卫
8function isUser(obj: any): obj is User {
9  return obj && typeof obj.id === 'number' && typeof obj.name === 'string';
10}
11
12if (isUser(data)) {
13  // TypeScript 知道这里 data 是 User 类型
14  console.log(data.name);
15}

3. 合理使用枚举

typescript
1// ✅ 使用 const 枚举提升性能
2const enum Color {
3  Red = "red",
4  Green = "green",
5  Blue = "blue"
6}
7
8// ✅ 或使用联合类型
9type Color = "red" | "green" | "blue";

🚀 在 React 中使用 TypeScript

组件类型定义

typescript
1import React, { FC, ReactNode } from 'react';
2
3interface ButtonProps {
4  children: ReactNode;
5  variant?: 'primary' | 'secondary';
6  size?: 'small' | 'medium' | 'large';
7  onClick?: () => void;
8  disabled?: boolean;
9}
10
11const Button: FC<ButtonProps> = ({
12  children,
13  variant = 'primary',
14  size = 'medium',
15  onClick,
16  disabled = false
17}) => {
18  return (
19    <button
20      className={`btn btn-${variant} btn-${size}`}
21      onClick={onClick}
22      disabled={disabled}
23    >
24      {children}
25    </button>
26  );
27};

Hooks 类型定义

typescript
1import { useState, useEffect } from 'react';
2
3interface User {
4  id: number;
5  name: string;
6  email: string;
7}
8
9// 自定义 Hook
10function useUser(userId: number) {
11  const [user, setUser] = useState<User | null>(null);
12  const [loading, setLoading] = useState(true);
13  const [error, setError] = useState<string | null>(null);
14
15  useEffect(() => {
16    async function fetchUser() {
17      try {
18        setLoading(true);
19        const response = await fetch(`/api/users/${userId}`);
20        if (!response.ok) {
21          throw new Error('Failed to fetch user');
22        }
23        const userData: User = await response.json();
24        setUser(userData);
25      } catch (err) {
26        setError(err instanceof Error ? err.message : 'Unknown error');
27      } finally {
28        setLoading(false);
29      }
30    }
31
32    fetchUser();
33  }, [userId]);
34
35  return { user, loading, error };
36}

🛠️ API 层类型安全

定义 API 响应类型

typescript
1// API 响应类型
2interface ApiResponse<T> {
3  data: T;
4  status: 'success' | 'error';
5  message?: string;
6}
7
8interface PaginatedResponse<T> extends ApiResponse<T[]> {
9  pagination: {
10    page: number;
11    limit: number;
12    total: number;
13    totalPages: number;
14  };
15}
16
17// API 服务
18class UserService {
19  static async getUser(id: number): Promise<User> {
20    const response = await fetch(`/api/users/${id}`);
21    const result: ApiResponse<User> = await response.json();
22    
23    if (result.status === 'error') {
24      throw new Error(result.message || 'Failed to fetch user');
25    }
26    
27    return result.data;
28  }
29
30  static async getUsers(page: number = 1): Promise<PaginatedResponse<User>> {
31    const response = await fetch(`/api/users?page=${page}`);
32    return response.json();
33  }
34}

⚡ 性能优化

类型导入优化

typescript
1// ✅ 使用 type-only 导入
2import type { User } from './types';
3import type { FC } from 'react';
4
5// ✅ 分离类型导入和值导入
6import { useState } from 'react';
7import type { ChangeEvent } from 'react';

避免过度类型化

typescript
1// ❌ 过度复杂的类型
2type ComplexType<T, U, V> = T extends U ? V extends string ? T : never : U;
3
4// ✅ 简单明了的类型
5type UserRole = 'admin' | 'user' | 'guest';

🔍 调试和工具

使用 TypeScript 编译器 API

typescript
1// 类型检查工具函数
2function assertIsNumber(value: unknown): asserts value is number {
3  if (typeof value !== 'number') {
4    throw new Error('Expected number');
5  }
6}
7
8// 使用
9function processValue(value: unknown) {
10  assertIsNumber(value);
11  // 这里 TypeScript 知道 value 是 number 类型
12  return value * 2;
13}

配置开发工具

json
1// .vscode/settings.json
2{
3  "typescript.preferences.importModuleSpecifier": "relative",
4  "typescript.suggest.autoImports": true,
5  "typescript.updateImportsOnFileMove.enabled": "always"
6}

📚 总结

TypeScript 最佳实践要点:

  1. 启用严格模式 - 获得最大的类型安全保障
  2. 合理使用泛型 - 提升代码复用性
  3. 避免 any 类型 - 使用类型守卫和断言
  4. 利用工具类型 - Partial、Pick、Omit 等
  5. 类型导入优化 - 区分类型和值的导入
  6. 组件类型定义 - 为 React 组件提供完整的类型支持

掌握这些实践,你就能写出更安全、更可维护的 TypeScript 代码!

评论讨论

使用 GitHub 账号登录即可参与讨论