第 98 章:接口(Interface)
学习目标
- 掌握接口的完整语法
- 学会对象的结构化类型(Structural Typing)
- 理解接口的继承与合并
- 掌握接口的高级特性(索引签名、函数类型)
一、接口基础
1.1 定义与使用
typescript
interface User {
id: number;
name: string;
email: string;
}
const u: User = {
id: 1,
name: 'Tom',
email: 'tom@example.com'
};1.2 与 type 的对比
typescript
// 用 interface
interface User {
name: string;
age: number;
}
// 用 type
type User = {
name: string;
age: number;
};结果几乎一样,但 interface 有两个特殊能力:
- 声明合并(declaration merging)
- 更清晰的面向对象语义
二、可选属性与只读属性
2.1 可选属性
typescript
interface User {
id: number;
name: string;
email?: string; // 可选
}
const u1: User = { id: 1, name: 'Tom' }; // ✅
const u2: User = { id: 1, name: 'Tom', email: 'a@b.c' }; // ✅2.2 只读属性
typescript
interface User {
readonly id: number;
name: string;
}
const u: User = { id: 1, name: 'Tom' };
u.name = 'Jerry'; // ✅
u.id = 2; // ❌ Cannot assign to 'id' because it is a read-only property2.3 完整写法
typescript
interface User {
readonly id: number; // 只读
name: string; // 必填可写
email?: string; // 可选
readonly tags?: string[]; // 可选只读
}三、索引签名
3.1 字符串索引
typescript
interface Dictionary {
[key: string]: string;
}
const dict: Dictionary = {
name: 'Tom',
email: 'tom@example.com',
// 任何 string key
};3.2 数字索引
typescript
interface StringArray {
[index: number]: string;
}
const arr: StringArray = ['a', 'b', 'c'];3.3 混合(已知字段 + 任意字段)
typescript
interface User {
name: string; // 已知字段
email: string; // 已知字段
[key: string]: string | number; // 任意字段
}
const u: User = {
name: 'Tom',
email: 'tom@example.com',
age: 18,
city: 'Beijing'
};四、接口继承
4.1 单继承
typescript
interface Animal {
name: string;
age: number;
}
interface Dog extends Animal {
breed: string; // 新增字段
}
const d: Dog = {
name: '旺财',
age: 3,
breed: '柴犬'
};4.2 多继承
typescript
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(`log: ${this.content}`); }
};4.3 继承 type 别名
typescript
type Base = { id: number; createdAt: Date };
interface User extends Base {
name: string;
}4.4 继承 + 添加可选
typescript
interface BaseConfig {
host: string;
port: number;
}
interface DevConfig extends BaseConfig {
debug: true; // 收窄类型
}
interface ProdConfig extends BaseConfig {
debug: false;
logger: 'loki' | 'file';
}五、声明合并(Declaration Merging)
interface 独有的特性:同名的多个 interface 自动合并。
5.1 基础合并
typescript
interface User {
name: string;
}
interface User {
age: number;
}
// 合并后等价于:
interface User {
name: string;
age: number;
}
const u: User = { name: 'Tom', age: 18 };5.2 合并规则
typescript
interface Box {
width: number;
}
// 后面的同名 interface 合并
interface Box {
height: number;
}
// 等价于
interface Box {
width: number;
height: number;
}
// 冲突字段会报错
interface Box {
width: string; // ❌ Subsequent property declarations must have the same type
}5.3 为第三方库扩展类型
typescript
// 假设已有第三方库导出 User
declare global {
interface User {
name: string;
}
}
// 想给 User 加字段(不修改源码)
declare global {
interface User {
email: string;
}
}
// 合并后 User 有 name + email这是给 window、Request、Response 等增加字段的标准做法。
六、接口描述函数
6.1 函数接口
typescript
interface GreetFunction {
(name: string): string;
}
const greet: GreetFunction = (name) => `Hello, ${name}!`;6.2 可调用接口(带属性)
typescript
interface Counter {
(): number; // 可调用
count: number; // 也有属性
reset(): void;
}
const counter = Object.assign(
function () { return counter.count++; },
{ count: 0, reset() { this.count = 0; } }
);七、接口描述类
7.1 implements
typescript
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
class Duck implements Flyable, Swimmable {
fly(): void {
console.log('鸭子飞');
}
swim(): void {
console.log('鸭子游');
}
}7.2 接口 vs 抽象类
typescript
// 抽象类
abstract class Animal {
abstract speak(): void;
move(): void { console.log('moving'); }
}
// 接口
interface Animal {
speak(): void;
}| 特性 | 接口 | 抽象类 |
|---|---|---|
| 多继承 | ✅ 可以 extends 多个 | ❌ 单继承 |
| 实现细节 | ❌ 不能有 | ✅ 可以有 |
| 运行时存在 | ❌ 编译后消失 | ✅ 编译后存在 |
| 何时用 | 描述"是什么" | 描述"怎么做" |
八、结构化类型(Structural Typing)
8.1 鸭子类型
typescript
interface User {
name: string;
age: number;
}
const tom = { name: 'Tom', age: 18 };
const jerry = { name: 'Jerry', age: 20, hobby: 'coding' };
function greet(u: User) {
console.log(u.name);
}
greet(tom); // ✅
greet(jerry); // ✅ 多了字段也接受TS 看的是形状(字段),不是名义类型。
8.2 兼容性
typescript
interface Named {
name: string;
}
class Person {
name: string = 'Tom';
age: number = 18;
}
const p = new Person();
const n: Named = p; // ✅ 结构匹配8.3 函数兼容性
typescript
type Handler = (a: number, b: number) => void;
function h1(a: number, b: number) {} // ✅
function h2(a: number, b: number, c: number) {} // ❌ 参数多了
function h3(a: number) {} // ❌ 参数少了
function h4(a: number, b: string) {} // ❌ 参数类型不同重要:返回值类型必须是子类型才能兼容。
九、接口组合实战
typescript
// 基础实体
interface BaseEntity {
id: number;
createdAt: Date;
updatedAt: Date;
}
// 用户
interface User extends BaseEntity {
name: string;
email: string;
role: 'admin' | 'user';
}
// 文章
interface Post extends BaseEntity {
title: string;
content: string;
authorId: number;
}
// 评论
interface Comment extends BaseEntity {
content: string;
postId: number;
authorId: number;
}
// 分页响应
interface PagedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
}
type UserList = PagedResponse<User>;
type PostList = PagedResponse<Post>;十、常见错误
10.1 对象字面量多余字段
typescript
interface User { name: string }
const u: User = { name: 'Tom', age: 18 }; // ❌
// ✅ 用变量
const obj = { name: 'Tom', age: 18 };
const u: User = obj;10.2 索引签名冲突
typescript
interface User {
name: string; // 已知字段 string
[key: string]: number; // ❌ 索引签名 string 不兼容
}10.3 接口作为值的导入
typescript
// ❌ 错误:接口是类型,不是值
import { User } from './types';
user.id; // ❌ Cannot use namespace 'User' as a type
// ✅ 正确
import type { User } from './types';十一、本章小结
| 要点 | 关键 |
|---|---|
| 接口定义 | interface User { name: string } |
| 属性 | 必选 / 可选 ? / 只读 readonly |
| 索引签名 | [key: string]: any 任意字段 |
| 继承 | extends 支持单继承和多继承 |
| 声明合并 | 同名 interface 自动合并 |
| 结构化类型 | 看形状不看名义 |
| implements | 用接口约束类的方法 |
动手练习
- 基础接口:设计一个
Article接口,包含id/title/content/author/publishedAt - 继承:让
FeaturedArticle继承Article,添加featured: boolean字段 - 声明合并:写两个同名 interface,验证会自动合并
推荐阅读
- 📖 TypeScript Handbook - Object Types — 接口详解
- 📖 TypeScript Handbook - Declaration Merging — 声明合并
- 🌐 TypeScript Structural Typing — 结构化类型
下一章:第 99 章:枚举(Enum) →