接口的基本概念与作用
接口(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';