4.TypeScript接口深度解析:构建结构化类型约束的利器

小鱼
2025-08-26 09:13:53
TypeScript

接口的基本概念与作用

接口(Interface)在TypeScript中用于定义对象的形状 - 即对象应该包含哪些属性、属性的类型以及方法的签名。它是对对象状态和行为的抽象描述,让我们能够在编码阶段就定义好数据的结构约束。

基础接口定义

typescript

// 定义一个Person接口
interface Person {
  id: number;
  name: string;
  age: number;
  email?: string; // 可选属性
}

// 使用接口
const user: Person = {
  id: 1,
  name: "张三",
  age: 28,
  email: "zhangsan@example.com"
};

接口的核心价值在于:

  • 类型检查:确保对象符合预期的结构
  • 代码自文档化:清晰表达数据的预期格式
  • 智能提示:编辑器能够提供准确的自动完成

接口的高级特性

可选属性:灵活应对不同场景

在实际开发中,我们经常遇到某些属性可能存在也可能不存在的情况:

typescript

interface Product {
  id: number;
  name: string;
  price: number;
  description?: string; // 可选属性
  tags?: string[];      // 可选属性
}

// 两种使用方式都有效
const product1: Product = {
  id: 101,
  name: "笔记本电脑",
  price: 5999,
  description: "高性能笔记本电脑"
};

const product2: Product = {
  id: 102,
  name: "鼠标",
  price: 99
  // 没有description和tags属性
};

可选属性通过 ?符号标记,让接口定义更加灵活,同时保持类型安全。

只读属性:保护数据不被修改

对于某些不应该被修改的属性,可以使用 readonly修饰符:

typescript

interface Configuration {
  readonly apiKey: string;
  readonly version: string;
  maxConnections: number;
}

const config: Configuration = {
  apiKey: "abc123",
  version: "1.0.0",
  maxConnections: 10
};

config.maxConnections = 20; // 允许修改
// config.apiKey = "new-key"; // 错误:无法分配到"apiKey",因为它是只读属性

只读属性常用于配置对象、常量值或任何不应该在初始化后被修改的数据。

函数类型接口:定义方法签名

接口不仅可以描述对象的属性,还可以描述函数类型:

typescript

// 定义函数接口
interface StringFormatter {
  (input: string): string;
}

// 实现函数
const toUpperCase: StringFormatter = function(str: string): string {
  return str.toUpperCase();
};

const toLowerCase: StringFormatter = function(str: string): string {
  return str.toLowerCase();
};

// 使用
console.log(toUpperCase("hello")); // "HELLO"
console.log(toLowerCase("WORLD")); // "world"

函数类型接口特别适合定义回调函数或策略模式中的算法接口。

接口与类的关系

类实现接口

TypeScript中的类可以通过 implements关键字实现一个或多个接口:

typescript

// 定义接口
interface Vehicle {
  start(): void;
  stop(): void;
  getFuelLevel(): number;
}

// 实现接口
class Car implements Vehicle {
  private fuel: number = 100;
  
  start(): void {
    console.log("汽车启动");
  }
  
  stop(): void {
    console.log("汽车停止");
  }
  
  getFuelLevel(): number {
    return this.fuel;
  }
  
  // 可以有自己的额外方法
  honk(): void {
    console.log("嘟嘟!");
  }
}

// 使用
const myCar = new Car();
myCar.start();
console.log(`油量: ${myCar.getFuelLevel()}%`);

实现多个接口

一个类可以实现多个接口,从而具备多种能力:

typescript

interface Alarm {
  triggerAlarm(): void;
}

interface Lock {
  lock(): void;
  unlock(): void;
}

// 实现多个接口
class SecuritySystem implements Alarm, Lock {
  private isLocked: boolean = false;
  
  triggerAlarm(): void {
    console.log("警报响起!");
  }
  
  lock(): void {
    this.isLocked = true;
    console.log("系统已锁定");
  }
  
  unlock(): void {
    this.isLocked = false;
    console.log("系统已解锁");
  }
}

接口继承:构建类型层次结构

接口可以继承其他接口,从而组合成更复杂的类型定义:

typescript

// 基础接口
interface Entity {
  id: number;
  createdAt: Date;
}

// 扩展接口
interface User extends Entity {
  name: string;
  email: string;
  isActive: boolean;
}

// 进一步扩展
interface AdminUser extends User {
  permissions: string[];
  canEditSettings: boolean;
}

// 使用
const admin: AdminUser = {
  id: 1,
  createdAt: new Date(),
  name: "管理员",
  email: "admin@example.com",
  isActive: true,
  permissions: ["create", "update", "delete"],
  canEditSettings: true
};

接口继承让我们能够构建清晰的类型层次结构,提高代码的可维护性和可读性。

多重继承

TypeScript支持接口的多重继承,可以从多个接口组合功能:

typescript

interface Loggable {
  log(message: string): void;
}

interface Serializable {
  serialize(): string;
}

// 多重继承
interface Persistent extends Loggable, Serializable {
  save(): boolean;
}

class DatabaseRecord implements Persistent {
  log(message: string): void {
    console.log(`[LOG]: ${message}`);
  }
  
  serialize(): string {
    return JSON.stringify(this);
  }
  
  save(): boolean {
    // 保存逻辑
    console.log("数据已保存");
    return true;
  }
}

接口的实际应用场景

数据模型定义

typescript

// API响应数据模型
interface ApiResponse<T> {
  success: boolean;
  data: T;
  message?: string;
  code: number;
}

// 用户数据模型
interface User {
  id: number;
  username: string;
  profile: UserProfile;
}

interface UserProfile {
  avatar: string;
  bio?: string;
  location?: string;
}

// 使用
async function fetchUser(userId: number): Promise<ApiResponse<User>> {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

组件属性定义(React示例)

typescript

interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary' | 'danger';
  disabled?: boolean;
  size?: 'small' | 'medium' | 'large';
}

const Button: React.FC<ButtonProps> = ({
  label,
  onClick,
  variant = 'primary',
  disabled = false,
  size = 'medium'
}) => {
  // 组件实现
  return (
    <button
      className={`btn btn-${variant} btn-${size}`}
      onClick={onClick}
      disabled={disabled}
    >
      {label}
    </button>
  );
};

配置对象定义

typescript

interface AppConfig {
  api: {
    baseURL: string;
    timeout: number;
    retries: number;
  };
  features: {
    darkMode: boolean;
    analytics: boolean;
    notifications: boolean;
  };
  i18n: {
    defaultLocale: string;
    supportedLocales: string[];
  };
}

const config: AppConfig = {
  api: {
    baseURL: "https://api.example.com",
    timeout: 5000,
    retries: 3
  },
  features: {
    darkMode: true,
    analytics: false,
    notifications: true
  },
  i18n: {
    defaultLocale: "zh-CN",
    supportedLocales: ["zh-CN", "en-US", "ja-JP"]
  }
};

接口与类型别名的区别

虽然接口和类型别名(type)在很多情况下可以互换,但它们有一些重要区别:

特性 接口 (interface) 类型别名 (type)
扩展方式 使用 extends 继承 使用 & 交叉类型
合并声明 支持声明合并 不支持
实现类 可以被类实现 不能被类实现
描述类型 主要描述对象形状 可以描述任意类型

typescript

// 接口声明合并
interface Box {
  width: number;
}

interface Box {
  height: number;
}

// 结果: { width: number; height: number; }
const box: Box = { width: 100, height: 200 };

// 类型别名
type Dimension = {
  width: number;
  height: number;
};

// 联合类型(接口无法实现)
type Status = 'active' | 'inactive' | 'pending';
Copyright © 2025 aipanzhou.com All Rights Reserved.
备案号:黔ICP备2023000741号-1
贵公网安备 52022202000096号