接口(Interface)
概述
接口是 TypeScript 的核心特性之一,用于定义对象的结构和类型契约。
基本语法
定义接口
// 定义接口
interface User {
id: number;
name: string;
email: string;
}
// 使用接口
const user: User = {
id: 1,
name: 'John',
email: 'john@example.com'
};
可选属性
interface User {
id: number;
name: string;
email: string;
avatar?: string; // 可选属性
age?: number; // 可选属性
}
const user1: User = {
id: 1,
name: 'John',
email: 'john@example.com'
};
const user2: User = {
id: 2,
name: 'Jane',
email: 'jane@example.com',
avatar: 'https://example.com/avatar.jpg',
age: 25
};
只读属性
interface User {
readonly id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: 'John',
email: 'john@example.com'
};
user.name = 'Jane'; // 正确
// user.id = 2; // 错误:只读属性
方法定义
对象方法
interface User {
id: number;
name: string;
greet(): string;
setName(name: string): void;
}
const user: User = {
id: 1,
name: 'John',
greet() {
return `Hello, ${this.name}!`;
},
setName(name: string) {
this.name = name;
}
};
函数类型属性
interface MathOperation {
(a: number, b: number): number;
}
const add: MathOperation = (a, b) => a + b;
const multiply: MathOperation = (a, b) => a * b;
interface Config {
onSuccess: (data: any) => void;
onError: (error: Error) => void;
}
索引签名
数字索引
interface StringArray {
[index: number]: string;
}
const array: StringArray = ['hello', 'world'];
console.log(array[0]); // 'hello'
字符串索引
interface Dictionary {
[key: string]: number;
}
const dict: Dictionary = {
apple: 1,
banana: 2,
orange: 3
};
interface User {
id: number;
name: string;
[key: string]: string | number;
}
const user: User = {
id: 1,
name: 'John',
email: 'john@example.com',
age: 25
};
接口继承
单继承
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: number;
department: string;
}
const employee: Employee = {
name: 'John',
age: 25,
employeeId: 123,
department: 'Engineering'
};
多继承
interface Printable {
print(): void;
}
interface Loggable {
log(): void;
}
interface Document extends Printable, Loggable {
content: string;
}
const doc: Document = {
content: 'Hello',
print() {
console.log(this.content);
},
log() {
console.log('Document logged');
}
};
泛型接口
基本泛型接口
interface Repository<T> {
getById(id: number): T;
getAll(): T[];
save(item: T): void;
delete(id: number): void;
}
interface User {
id: number;
name: string;
}
const userRepo: Repository<User> = {
getById(id: number): User {
return { id, name: 'John' };
},
getAll(): User[] {
return [{ id: 1, name: 'John' }];
},
save(user: User): void {
console.log('Saving user', user);
},
delete(id: number): void {
console.log('Deleting user', id);
}
};
约束泛型接口
interface Entity {
id: number;
}
interface Repository<T extends Entity> {
getById(id: number): T | null;
save(item: T): void;
}
实际应用示例
1. API 响应接口
interface ApiResponse<T> {
success: boolean;
data: T;
message?: string;
timestamp: number;
}
interface User {
id: number;
name: string;
email: string;
}
type UserResponse = ApiResponse<User>;
type UsersResponse = ApiResponse<User[]>;
const response: UserResponse = {
success: true,
data: {
id: 1,
name: 'John',
email: 'john@example.com'
},
timestamp: Date.now()
};
2. 事件处理接口
interface EventHandler<T = any> {
(event: T): void;
}
interface EventMap {
click: MouseEvent;
focus: FocusEvent;
blur: FocusEvent;
submit: SubmitEvent;
}
class EventEmitter {
private handlers: Partial<Record<keyof EventMap, EventHandler[]>> = {};
on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): void {
if (!this.handlers[event]) {
this.handlers[event] = [];
}
this.handlers[event]!.push(handler);
}
emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {
this.handlers[event]?.forEach(handler => handler(data));
}
}
3. 配置接口
interface DatabaseConfig {
host: string;
port: number;
database: string;
username: string;
password: string;
ssl?: boolean;
pool?: {
min: number;
max: number;
};
}
interface AppConfig {
database: DatabaseConfig;
redis?: {
host: string;
port: number;
};
logging: {
level: 'debug' | 'info' | 'warn' | 'error';
file?: string;
};
}
const config: AppConfig = {
database: {
host: 'localhost',
port: 5432,
database: 'myapp',
username: 'admin',
password: 'secret'
},
logging: {
level: 'info'
}
};
最佳实践
- 使用接口定义对象类型:比类型别名更清晰
- 使用可选属性:提高灵活性
- 使用只读属性:保护不可变数据
- 使用泛型接口:提高复用性
// 好的做法
interface User {
readonly id: number;
name: string;
email: string;
avatar?: string;
}
// 避免
type User = {
id: number;
name: string;
email: string;
avatar: string | undefined;
};
参考
目录