TypeScript 高级特性:构建类型安全的现代应用

深入探索 TypeScript 的高级特性,包括泛型、装饰器、模块系统、类型推断等,帮助开发者构建更加健壮和可维护的应用程序。

2025年9月18日
DocsLib Team
TypeScriptJavaScript类型系统前端开发静态类型

TypeScript 高级特性:构建类型安全的现代应用

TypeScript 简介

TypeScript 是由 Microsoft 开发的 JavaScript 的超集,它添加了静态类型定义。TypeScript 代码会被编译成纯 JavaScript,可以在任何支持 JavaScript 的环境中运行。

TypeScript 的优势

  1. 静态类型检查:在编译时发现错误,而不是运行时
  2. 更好的 IDE 支持:智能提示、重构、导航等
  3. 增强的代码可读性:类型注解使代码更易理解
  4. 更好的重构支持:类型系统帮助安全地重构代码
  5. 渐进式采用:可以逐步将 JavaScript 项目迁移到 TypeScript
  6. 丰富的生态系统:大量的类型定义文件

基础类型系统

基本类型

// 基本类型
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];

// 枚举
enum Color {
  Red,
  Green,
  Blue,
}
let c: Color = Color.Green;

// Any 类型(尽量避免使用)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;

// Void 类型
function warnUser(): void {
  console.log("This is my warning message");
}

// Null 和 Undefined
let u: undefined = undefined;
let n: null = null;

// Never 类型
function error(message: string): never {
  throw new Error(message);
}

// Object 类型
let obj: object = { name: "John", age: 30 };

联合类型和交叉类型

// 联合类型
type StringOrNumber = string | number;
type Theme = "light" | "dark" | "auto";

function formatValue(value: StringOrNumber): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value.toString();
}

// 交叉类型
interface Person {
  name: string;
  age: number;
}

interface Employee {
  employeeId: string;
  department: string;
}

type PersonEmployee = Person & Employee;

const employee: PersonEmployee = {
  name: "John Doe",
  age: 30,
  employeeId: "EMP001",
  department: "Engineering",
};

// 类型守卫
function isString(value: StringOrNumber): value is string {
  return typeof value === "string";
}

function processValue(value: StringOrNumber) {
  if (isString(value)) {
    // TypeScript 知道这里 value 是 string 类型
    console.log(value.toUpperCase());
  } else {
    // TypeScript 知道这里 value 是 number 类型
    console.log(value.toFixed(2));
  }
}

泛型 (Generics)

泛型是 TypeScript 最强大的特性之一,它允许我们创建可重用的组件。

基础泛型

// 泛型函数
function identity<T>(arg: T): T {
  return arg;
}

// 使用泛型函数
let output1 = identity<string>("myString");
let output2 = identity<number>(100);

// 类型推断
let output3 = identity("myString"); // TypeScript 自动推断 T 为 string

// 泛型数组
function loggingIdentity<T>(arg: T[]): T[] {
  console.log(arg.length);
  return arg;
}

// 泛型接口
interface GenericIdentityFn<T> {
  (arg: T): T;
}

function identity2<T>(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity2;

泛型类

// 泛型类
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;

  constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
    this.zeroValue = zeroValue;
    this.add = addFn;
  }
}

// 使用泛型类
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
let myGenericString = new GenericNumber<string>("", (x, y) => x + y);

// 数据结构示例:栈
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }

  isEmpty(): boolean {
    return this.items.length === 0;
  }

  size(): number {
    return this.items.length;
  }

  clear(): void {
    this.items = [];
  }

  toArray(): T[] {
    return [...this.items];
  }
}

// 使用栈
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);

console.log(numberStack.peek()); // 3
console.log(numberStack.pop());  // 3
console.log(numberStack.size()); // 2

const stringStack = new Stack<string>();
stringStack.push("hello");
stringStack.push("world");

泛型约束

// 泛型约束
interface Lengthwise {
  length: number;
}

function loggingIdentity2<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // 现在我们知道 arg 有 length 属性
  return arg;
}

// 使用约束
loggingIdentity2("hello"); // 字符串有 length 属性
loggingIdentity2([1, 2, 3]); // 数组有 length 属性
// loggingIdentity2(3); // 错误:number 没有 length 属性

// 在泛型约束中使用类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

let person = { name: "John", age: 30, city: "New York" };
let name = getProperty(person, "name"); // string
let age = getProperty(person, "age");   // number
// let invalid = getProperty(person, "invalid"); // 错误:参数类型不匹配

// 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;

type A = NonNullable<string | null | undefined>; // string
type B = NonNullable<number | null>; // number

// 映射类型
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

interface User {
  id: number;
  name: string;
  email: string;
}

type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;

// 使用映射类型
const user: User = { id: 1, name: "John", email: "john@example.com" };
const readonlyUser: ReadonlyUser = user;
// readonlyUser.name = "Jane"; // 错误:只读属性

const partialUser: PartialUser = { name: "Jane" }; // 只需要部分属性

高级类型操作

工具类型

// 内置工具类型示例
interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: Date;
}

// Partial<T> - 将所有属性变为可选
type PartialTodo = Partial<Todo>;
function updateTodo(todo: Todo, fieldsToUpdate: PartialTodo): Todo {
  return { ...todo, ...fieldsToUpdate };
}

// Required<T> - 将所有属性变为必需
type RequiredTodo = Required<PartialTodo>;

// Readonly<T> - 将所有属性变为只读
type ReadonlyTodo = Readonly<Todo>;

// Pick<T, K> - 选择特定属性
type TodoPreview = Pick<Todo, "title" | "completed">;
const preview: TodoPreview = {
  title: "Clean room",
  completed: false,
};

// Omit<T, K> - 排除特定属性
type TodoWithoutId = Omit<Todo, "createdAt">;

// Record<K, T> - 创建具有特定键和值类型的对象类型
type TodoStatus = "pending" | "in-progress" | "completed";
type TodoStatusRecord = Record<TodoStatus, number>;

const statusCount: TodoStatusRecord = {
  pending: 5,
  "in-progress": 3,
  completed: 10,
};

// Exclude<T, U> - 从联合类型中排除特定类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<string | number | (() => void), Function>; // string | number

// Extract<T, U> - 从联合类型中提取特定类型
type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T3 = Extract<string | number | (() => void), Function>; // () => void

// ReturnType<T> - 获取函数返回类型
function createUser(name: string, age: number) {
  return { name, age, id: Math.random() };
}

type User2 = ReturnType<typeof createUser>; // { name: string; age: number; id: number; }

// Parameters<T> - 获取函数参数类型
type CreateUserParams = Parameters<typeof createUser>; // [string, number]

自定义工具类型

// 深度只读
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

interface NestedObject {
  a: {
    b: {
      c: string;
    };
  };
}

type ReadonlyNested = DeepReadonly<NestedObject>;
// 所有嵌套属性都是只读的

// 可空类型
type Nullable<T> = T | null;
type Optional<T> = T | undefined;
type Maybe<T> = T | null | undefined;

// 函数重载类型
type FunctionOverload<T> = T extends {
  (...args: infer A1): infer R1;
  (...args: infer A2): infer R2;
  (...args: infer A3): infer R3;
}
  ? {
      (...args: A1): R1;
      (...args: A2): R2;
      (...args: A3): R3;
    }
  : T extends {
      (...args: infer A1): infer R1;
      (...args: infer A2): infer R2;
    }
  ? {
      (...args: A1): R1;
      (...args: A2): R2;
    }
  : T extends (...args: infer A): infer R
  ? (...args: A) => R
  : never;

// 键值对类型
type KeyValuePair<T> = {
  [K in keyof T]: {
    key: K;
    value: T[K];
  };
}[keyof T];

type UserKeyValue = KeyValuePair<User>;
// { key: "id"; value: number; } | { key: "name"; value: string; } | { key: "email"; value: string; }

// 条件类型示例
type IsArray<T> = T extends any[] ? true : false;
type Test1 = IsArray<string[]>; // true
type Test2 = IsArray<string>; // false

// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]

装饰器 (Decorators)

装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、访问符、属性或参数上。

类装饰器

// 启用装饰器支持需要在 tsconfig.json 中设置 "experimentalDecorators": true

// 简单的类装饰器
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

// 装饰器工厂
function classDecorator<T extends { new (...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor {
    newProperty = "new property";
    hello = "override";
  };
}

@classDecorator
class GreeterWithDecorator {
  property = "property";
  hello: string;
  constructor(m: string) {
    this.hello = m;
  }
}

// 日志装饰器
function logClass(target: any) {
  console.log(`Class ${target.name} was created`);
  return target;
}

@logClass
class LoggedClass {
  constructor(public name: string) {}
}

方法装饰器

// 方法装饰器
function log(
  target: any,
  propertyName: string,
  descriptor: PropertyDescriptor
) {
  const method = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${propertyName} with arguments:`, args);
    const result = method.apply(this, args);
    console.log(`Method ${propertyName} returned:`, result);
    return result;
  };
}

// 性能监控装饰器
function measure(
  target: any,
  propertyName: string,
  descriptor: PropertyDescriptor
) {
  const method = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = method.apply(this, args);
    const end = performance.now();
    console.log(`${propertyName} took ${end - start} milliseconds`);
    return result;
  };
}

// 缓存装饰器
function cache(
  target: any,
  propertyName: string,
  descriptor: PropertyDescriptor
) {
  const method = descriptor.value;
  const cacheMap = new Map();

  descriptor.value = function (...args: any[]) {
    const key = JSON.stringify(args);
    if (cacheMap.has(key)) {
      console.log(`Cache hit for ${propertyName}`);
      return cacheMap.get(key);
    }

    const result = method.apply(this, args);
    cacheMap.set(key, result);
    console.log(`Cache miss for ${propertyName}, result cached`);
    return result;
  };
}

class Calculator {
  @log
  @measure
  add(a: number, b: number): number {
    return a + b;
  }

  @cache
  fibonacci(n: number): number {
    if (n <= 1) return n;
    return this.fibonacci(n - 1) + this.fibonacci(n - 2);
  }
}

const calc = new Calculator();
calc.add(2, 3);
calc.fibonacci(10);
calc.fibonacci(10); // 第二次调用会使用缓存

属性装饰器

// 属性装饰器
function readonly(target: any, propertyName: string) {
  Object.defineProperty(target, propertyName, {
    writable: false,
  });
}

// 验证装饰器
function validate(validationFn: (value: any) => boolean) {
  return function (target: any, propertyName: string) {
    let value = target[propertyName];

    const getter = () => value;
    const setter = (newValue: any) => {
      if (!validationFn(newValue)) {
        throw new Error(`Invalid value for ${propertyName}: ${newValue}`);
      }
      value = newValue;
    };

    Object.defineProperty(target, propertyName, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true,
    });
  };
}

// 格式化装饰器
function format(formatFn: (value: any) => any) {
  return function (target: any, propertyName: string) {
    let value = target[propertyName];

    const getter = () => value;
    const setter = (newValue: any) => {
      value = formatFn(newValue);
    };

    Object.defineProperty(target, propertyName, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true,
    });
  };
}

class Person {
  @readonly
  id: number = Math.random();

  @validate((value: string) => value.length >= 2)
  @format((value: string) => value.trim().toLowerCase())
  name: string;

  @validate((value: number) => value >= 0 && value <= 150)
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

const person = new Person("  John Doe  ", 30);
console.log(person.name); // "john doe"
// person.id = 123; // 错误:只读属性
// person.age = -5; // 错误:验证失败

模块系统

ES6 模块

// math.ts - 导出模块
export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b: number): number {
  return a - b;
}

export const PI = 3.14159;

// 默认导出
export default class Calculator {
  add = add;
  subtract = subtract;
}

// 类型导出
export interface MathOperation {
  (a: number, b: number): number;
}

export type OperationType = 'add' | 'subtract' | 'multiply' | 'divide';

// utils.ts - 重新导出
export { add, subtract } from './math';
export { default as Calculator } from './math';

// main.ts - 导入模块
import Calculator, { add, subtract, PI, MathOperation } from './math';
import * as MathUtils from './math';

const calc = new Calculator();
console.log(calc.add(2, 3));
console.log(add(5, 3));
console.log(PI);

// 动态导入
async function loadMath() {
  const mathModule = await import('./math');
  return new mathModule.default();
}

命名空间

// 命名空间定义
namespace Geometry {
  export interface Point {
    x: number;
    y: number;
  }

  export interface Circle {
    center: Point;
    radius: number;
  }

  export function distance(p1: Point, p2: Point): number {
    return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
  }

  export function area(circle: Circle): number {
    return Math.PI * circle.radius * circle.radius;
  }

  // 嵌套命名空间
  export namespace Shapes {
    export class Rectangle {
      constructor(public width: number, public height: number) {}

      area(): number {
        return this.width * this.height;
      }
    }

    export class Triangle {
      constructor(
        public base: number,
        public height: number
      ) {}

      area(): number {
        return (this.base * this.height) / 2;
      }
    }
  }
}

// 使用命名空间
const point1: Geometry.Point = { x: 0, y: 0 };
const point2: Geometry.Point = { x: 3, y: 4 };
const circle: Geometry.Circle = { center: point1, radius: 5 };

console.log(Geometry.distance(point1, point2)); // 5
console.log(Geometry.area(circle)); // 78.54

const rect = new Geometry.Shapes.Rectangle(10, 20);
console.log(rect.area()); // 200

// 命名空间别名
import Shapes = Geometry.Shapes;
const triangle = new Shapes.Triangle(10, 15);
console.log(triangle.area()); // 75

声明文件和类型定义

声明文件

// types.d.ts - 全局类型声明
declare global {
  interface Window {
    myGlobalFunction: (arg: string) => void;
    myGlobalVariable: number;
  }

  var ENV: 'development' | 'production' | 'test';
}

// 模块声明
declare module 'my-library' {
  export function doSomething(arg: string): number;
  export interface MyInterface {
    prop: string;
  }
}

// 扩展现有模块
declare module 'express' {
  interface Request {
    user?: {
      id: string;
      name: string;
    };
  }
}

// jQuery 类型声明示例
declare var $: {
  (selector: string): {
    click(handler: () => void): void;
    text(value?: string): string | void;
    addClass(className: string): void;
  };
  ajax(settings: {
    url: string;
    method?: string;
    data?: any;
    success?: (data: any) => void;
    error?: (error: any) => void;
  }): void;
};

// 使用声明的类型
window.myGlobalFunction('hello');
console.log(window.myGlobalVariable);

$('#myButton').click(() => {
  console.log('Button clicked');
});

$.ajax({
  url: '/api/data',
  method: 'GET',
  success: (data) => {
    console.log(data);
  }
});

类型断言和类型守卫

// 类型断言
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
// 或者使用尖括号语法(在 JSX 中不可用)
let strLength2: number = (<string>someValue).length;

// 非空断言
function processUser(user: User | null) {
  // 我们确定 user 不为 null
  console.log(user!.name);
}

// 类型守卫函数
function isString(value: any): value is string {
  return typeof value === 'string';
}

function isNumber(value: any): value is number {
  return typeof value === 'number';
}

function isUser(obj: any): obj is User {
  return obj && typeof obj.name === 'string' && typeof obj.age === 'number';
}

// 使用类型守卫
function processValue(value: string | number | User) {
  if (isString(value)) {
    // TypeScript 知道 value 是 string
    console.log(value.toUpperCase());
  } else if (isNumber(value)) {
    // TypeScript 知道 value 是 number
    console.log(value.toFixed(2));
  } else if (isUser(value)) {
    // TypeScript 知道 value 是 User
    console.log(value.name);
  }
}

// in 操作符类型守卫
interface Bird {
  fly(): void;
  layEggs(): void;
}

interface Fish {
  swim(): void;
  layEggs(): void;
}

function move(pet: Bird | Fish) {
  if ('fly' in pet) {
    // TypeScript 知道 pet 是 Bird
    pet.fly();
  } else {
    // TypeScript 知道 pet 是 Fish
    pet.swim();
  }
}

// instanceof 类型守卫
class Dog {
  bark() {
    console.log('Woof!');
  }
}

class Cat {
  meow() {
    console.log('Meow!');
  }
}

function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}

实际应用示例

API 客户端

// API 响应类型
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
  timestamp: string;
}

interface PaginatedResponse<T> extends ApiResponse<T[]> {
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
  };
}

// 用户相关类型
interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  createdAt: string;
  updatedAt: string;
}

interface CreateUserRequest {
  name: string;
  email: string;
  password: string;
}

interface UpdateUserRequest extends Partial<Omit<User, 'id' | 'createdAt' | 'updatedAt'>> {}

// HTTP 客户端类
class HttpClient {
  private baseURL: string;
  private defaultHeaders: Record<string, string>;

  constructor(baseURL: string, defaultHeaders: Record<string, string> = {}) {
    this.baseURL = baseURL;
    this.defaultHeaders = defaultHeaders;
  }

  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<T> {
    const url = `${this.baseURL}${endpoint}`;
    const config: RequestInit = {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...this.defaultHeaders,
        ...options.headers,
      },
    };

    try {
      const response = await fetch(url, config);
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      console.error('Request failed:', error);
      throw error;
    }
  }

  async get<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint, { method: 'GET' });
  }

  async post<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  async put<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: JSON.stringify(data),
    });
  }

  async delete<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint, { method: 'DELETE' });
  }
}

// API 服务类
class UserService {
  private http: HttpClient;

  constructor(http: HttpClient) {
    this.http = http;
  }

  async getUsers(page = 1, limit = 10): Promise<PaginatedResponse<User>> {
    return this.http.get<PaginatedResponse<User>>(
      `/users?page=${page}&limit=${limit}`
    );
  }

  async getUserById(id: string): Promise<ApiResponse<User>> {
    return this.http.get<ApiResponse<User>>(`/users/${id}`);
  }

  async createUser(userData: CreateUserRequest): Promise<ApiResponse<User>> {
    return this.http.post<ApiResponse<User>>('/users', userData);
  }

  async updateUser(
    id: string,
    userData: UpdateUserRequest
  ): Promise<ApiResponse<User>> {
    return this.http.put<ApiResponse<User>>(`/users/${id}`, userData);
  }

  async deleteUser(id: string): Promise<ApiResponse<null>> {
    return this.http.delete<ApiResponse<null>>(`/users/${id}`);
  }
}

// 使用示例
const httpClient = new HttpClient('https://api.example.com', {
  'Authorization': 'Bearer your-token-here'
});

const userService = new UserService(httpClient);

// 使用服务
async function example() {
  try {
    // 获取用户列表
    const usersResponse = await userService.getUsers(1, 20);
    console.log('Users:', usersResponse.data);
    console.log('Total:', usersResponse.pagination.total);

    // 创建新用户
    const newUser = await userService.createUser({
      name: 'John Doe',
      email: 'john@example.com',
      password: 'securepassword'
    });
    console.log('Created user:', newUser.data);

    // 更新用户
    const updatedUser = await userService.updateUser(newUser.data.id, {
      name: 'Jane Doe'
    });
    console.log('Updated user:', updatedUser.data);

  } catch (error) {
    console.error('Error:', error);
  }
}

状态管理

// 状态管理类型定义
type ActionType = 'SET_LOADING' | 'SET_ERROR' | 'SET_DATA' | 'RESET';

interface Action<T = any> {
  type: ActionType;
  payload?: T;
}

interface State<T> {
  data: T | null;
  loading: boolean;
  error: string | null;
}

// 状态管理类
class Store<T> {
  private state: State<T>;
  private listeners: Array<(state: State<T>) => void> = [];

  constructor(initialState?: Partial<State<T>>) {
    this.state = {
      data: null,
      loading: false,
      error: null,
      ...initialState,
    };
  }

  getState(): State<T> {
    return { ...this.state };
  }

  dispatch(action: Action): void {
    this.state = this.reducer(this.state, action);
    this.notifyListeners();
  }

  subscribe(listener: (state: State<T>) => void): () => void {
    this.listeners.push(listener);
    
    // 返回取消订阅函数
    return () => {
      const index = this.listeners.indexOf(listener);
      if (index > -1) {
        this.listeners.splice(index, 1);
      }
    };
  }

  private reducer(state: State<T>, action: Action): State<T> {
    switch (action.type) {
      case 'SET_LOADING':
        return { ...state, loading: action.payload, error: null };
      
      case 'SET_ERROR':
        return { ...state, error: action.payload, loading: false };
      
      case 'SET_DATA':
        return { ...state, data: action.payload, loading: false, error: null };
      
      case 'RESET':
        return { data: null, loading: false, error: null };
      
      default:
        return state;
    }
  }

  private notifyListeners(): void {
    this.listeners.forEach(listener => listener(this.state));
  }
}

// 异步操作管理
class AsyncStore<T> extends Store<T> {
  async fetchData(fetchFn: () => Promise<T>): Promise<void> {
    this.dispatch({ type: 'SET_LOADING', payload: true });
    
    try {
      const data = await fetchFn();
      this.dispatch({ type: 'SET_DATA', payload: data });
    } catch (error) {
      this.dispatch({ 
        type: 'SET_ERROR', 
        payload: error instanceof Error ? error.message : 'Unknown error'
      });
    }
  }
}

// 使用示例
interface TodoItem {
  id: string;
  title: string;
  completed: boolean;
  createdAt: Date;
}

const todoStore = new AsyncStore<TodoItem[]>();

// 订阅状态变化
const unsubscribe = todoStore.subscribe((state) => {
  console.log('Todo state changed:', state);
  
  if (state.loading) {
    console.log('Loading todos...');
  } else if (state.error) {
    console.error('Error loading todos:', state.error);
  } else if (state.data) {
    console.log('Todos loaded:', state.data);
  }
});

// 模拟获取数据
async function fetchTodos(): Promise<TodoItem[]> {
  // 模拟 API 调用
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  return [
    {
      id: '1',
      title: 'Learn TypeScript',
      completed: false,
      createdAt: new Date()
    },
    {
      id: '2',
      title: 'Build a project',
      completed: true,
      createdAt: new Date()
    }
  ];
}

// 使用 store
todoStore.fetchData(fetchTodos);

// 稍后取消订阅
setTimeout(() => {
  unsubscribe();
}, 5000);

最佳实践

1. 类型设计原则

// ✅ 好的实践:使用具体的类型
interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
}

// ❌ 避免:过度使用 any
interface BadUser {
  id: any;
  name: any;
  email: any;
  role: any;
}

// ✅ 好的实践:使用联合类型
type Status = 'pending' | 'approved' | 'rejected';

// ✅ 好的实践:使用泛型提高复用性
interface Repository<T> {
  findById(id: string): Promise<T | null>;
  findAll(): Promise<T[]>;
  create(entity: Omit<T, 'id'>): Promise<T>;
  update(id: string, entity: Partial<T>): Promise<T>;
  delete(id: string): Promise<void>;
}

// ✅ 好的实践:使用索引签名处理动态属性
interface Config {
  apiUrl: string;
  timeout: number;
  [key: string]: string | number | boolean;
}

2. 错误处理

// 自定义错误类型
class AppError extends Error {
  constructor(
    message: string,
    public code: string,
    public statusCode: number = 500
  ) {
    super(message);
    this.name = 'AppError';
  }
}

class ValidationError extends AppError {
  constructor(message: string, public field: string) {
    super(message, 'VALIDATION_ERROR', 400);
    this.name = 'ValidationError';
  }
}

// 结果类型
type Result<T, E = Error> = 
  | { success: true; data: T }
  | { success: false; error: E };

// 安全的异步函数
async function safeAsync<T>(fn: () => Promise<T>): Promise<Result<T>> {
  try {
    const data = await fn();
    return { success: true, data };
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error : new Error(String(error))
    };
  }
}

// 使用示例
async function fetchUserSafely(id: string): Promise<Result<User>> {
  return safeAsync(async () => {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      throw new AppError('User not found', 'USER_NOT_FOUND', 404);
    }
    return response.json();
  });
}

// 使用结果
async function handleUser(id: string) {
  const result = await fetchUserSafely(id);
  
  if (result.success) {
    console.log('User:', result.data);
  } else {
    console.error('Error:', result.error.message);
  }
}

3. 配置和环境

// 环境配置类型
interface DatabaseConfig {
  host: string;
  port: number;
  database: string;
  username: string;
  password: string;
}

interface ApiConfig {
  baseUrl: string;
  timeout: number;
  retries: number;
}

interface AppConfig {
  env: 'development' | 'staging' | 'production';
  port: number;
  database: DatabaseConfig;
  api: ApiConfig;
  features: {
    enableLogging: boolean;
    enableMetrics: boolean;
    enableCache: boolean;
  };
}

// 配置验证
function validateConfig(config: any): config is AppConfig {
  return (
    config &&
    typeof config.env === 'string' &&
    ['development', 'staging', 'production'].includes(config.env) &&
    typeof config.port === 'number' &&
    config.database &&
    typeof config.database.host === 'string' &&
    typeof config.database.port === 'number'
    // ... 更多验证
  );
}

// 配置加载器
class ConfigLoader {
  static load(): AppConfig {
    const config = {
      env: process.env.NODE_ENV || 'development',
      port: parseInt(process.env.PORT || '3000'),
      database: {
        host: process.env.DB_HOST || 'localhost',
        port: parseInt(process.env.DB_PORT || '5432'),
        database: process.env.DB_NAME || 'myapp',
        username: process.env.DB_USER || 'user',
        password: process.env.DB_PASS || 'password',
      },
      api: {
        baseUrl: process.env.API_BASE_URL || 'http://localhost:3000',
        timeout: parseInt(process.env.API_TIMEOUT || '5000'),
        retries: parseInt(process.env.API_RETRIES || '3'),
      },
      features: {
        enableLogging: process.env.ENABLE_LOGGING === 'true',
        enableMetrics: process.env.ENABLE_METRICS === 'true',
        enableCache: process.env.ENABLE_CACHE === 'true',
      },
    };

    if (!validateConfig(config)) {
      throw new Error('Invalid configuration');
    }

    return config;
  }
}

总结

TypeScript 的高级特性为现代 JavaScript 开发提供了强大的类型安全保障和开发体验。通过掌握泛型、装饰器、高级类型操作、模块系统等特性,开发者可以构建更加健壮、可维护和可扩展的应用程序。

关键要点

  1. 类型安全:利用 TypeScript 的类型系统在编译时捕获错误
  2. 代码复用:使用泛型和高级类型创建可重用的组件
  3. 开发体验:享受更好的 IDE 支持和代码提示
  4. 渐进式采用:可以逐步将现有 JavaScript 项目迁移到 TypeScript
  5. 生态系统:利用丰富的类型定义文件和社区资源

掌握这些高级特性,你将能够充分发挥 TypeScript 的威力,构建出色的现代 Web 应用程序。

返回博客列表
感谢阅读!