📚 现代前端开发 目录
阶段2:工程化
第 11 / 35 课

TypeScript基础

给JavaScript加上类型保护

📖 核心概念

💻 代码实现

TypeScript核心类型 ✅ typescript
// 基础类型与接口
interface User {
  readonly id: number;
  name: string;
  email: string;
  age?: number;  // 可选属性
  role: 'admin' | 'editor' | 'viewer'; // 字面量联合类型
  preferences: {
    theme: 'light' | 'dark';
    language: string;
  };
}

// 类型别名与工具类型
type Nullable<T> = T | null;
type UserKeys = keyof User; // "id" | "name" | "email" | ...
type PartialUser = Partial<User>; // 所有属性可选
type RequiredUser = Required<User>; // 所有属性必填
type UserPreview = Pick<User, 'id' | 'name'>; // 只取部分属性
type UserCreate = Omit<User, 'id'>; // 排除id

// 交叉类型 - 组合多个类型
type Timestamps = {
  createdAt: Date;
  updatedAt: Date;
};
type UserWithTimestamps = User & Timestamps;

// 函数类型
type AsyncResult<T> = Promise<{ data: T; error: null } | { data: null; error: Error }>;

async function fetchUser(id: number): AsyncResult<User> {
  try {
    const response = await fetch(\`/api/users/\${id}\`);
    const data = await response.json() as User;
    return { data, error: null };
  } catch (error) {
    return { data: null, error: error as Error };
  }
}

// 函数重载
function createElement(tag: 'input', attrs: InputAttributes): HTMLInputElement;
function createElement(tag: 'div', attrs: DivAttributes): HTMLDivElement;
function createElement(tag: string, attrs: Record<string, unknown>): HTMLElement {
  const el = document.createElement(tag);
  Object.assign(el, attrs);
  return el;
}
类型守卫与类 ✅ typescript
// 类型守卫
function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value &&
    'email' in value
  );
}

// 判别联合类型
type ApiResponse<T> =
  | { status: 'success'; data: T; message?: string }
  | { status: 'error'; error: { code: number; message: string } }
  | { status: 'loading' };

function handleResponse<T>(response: ApiResponse<T>) {
  switch (response.status) {
    case 'success':
      console.log('数据:', response.data); // TypeScript知道data存在
      break;
    case 'error':
      console.error('错误:', response.error.message); // TypeScript知道error存在
      break;
    case 'loading':
      console.log('加载中...');
      break;
  }
}

// 类与修饰符
class Repository<T extends { id: number }> {
  private items: Map<number, T> = new Map();
  protected events: EventEmitter = new EventEmitter();

  constructor(public readonly name: string) {}

  add(item: T): this {
    this.items.set(item.id, item);
    this.events.emit('add', item);
    return this; // 链式调用
  }

  findById(id: number): T | undefined {
    return this.items.get(id);
  }

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

  update(id: number, partial: Partial<T>): T | undefined {
    const item = this.findById(id);
    if (!item) return undefined;
    Object.assign(item, partial);
    this.events.emit('update', item);
    return item;
  }

  delete(id: number): boolean {
    const deleted = this.items.delete(id);
    if (deleted) this.events.emit('delete', id);
    return deleted;
  }

  // 静态工厂方法
  static fromArray<T extends { id: number }>(items: T[]): Repository<T> {
    const repo = new Repository<T>('auto');
    items.forEach(item => repo.add(item));
    return repo;
  }
}

// 使用
const userRepo = Repository.fromArray([
  { id: 1, name: '张三', email: 'zhang@test.com' },
  { id: 2, name: '李四', email: 'li@test.com' },
]);

🔍 TypeScript配置要点

tsconfig.json的关键配置:strict模式开启所有严格检查、noUncheckedIndexedAccess防止数组越界、verbatimModuleStyle确保类型导入导出一致。推荐使用最严格的配置,虽然初期需要更多类型标注,但能避免大量运行时错误。

🎯 练习任务

🏆 成就解锁
类型守护者 — 掌握TypeScript类型系统,编写类型安全的前端代码