TypeScript 接口
interface 是 TS 里描述"对象形状"最常用的工具——它定义一个对象应该有哪些字段、字段是什么类型。前后端约定的数据结构、函数的参数对象、组件的 props,几乎都用 interface 描述。学会它,你就能给任意复杂的对象定义类型。
1. 基本用法
用 interface 关键字声明一个接口,里面列出字段名和类型。然后用它约束变量或参数:
// interface 描述"一个对象应该长什么样"
interface User {
id: number;
name: string;
age: number;
}
// 用 interface 约束变量/参数的类型
const u: User = { id: 1, name: "小明", age: 20 };
function greet(user: User): string {
return `你好, ${user.name}!`;
}
console.log(greet(u)); // 你好, 小明!
// ❌ 少写字段会报错
const bad: User = { id: 2, name: "小红" };
// 报错:缺少属性 "age"
// ❌ 多写字段也会报错
const bad2: User = { id: 3, name: "小刚", age: 21, extra: 1 };
// 报错:对象文字可以只指定已知属性,"extra" 不存在TS 会强制检查:字段数量必须完全一致(不能多也不能少),类型也必须匹配。这种"结构必须吻合"的检查,是 TS 治病救人的主战场。
2. 可选属性:加问号
有些字段不一定出现,比如用户的昵称、文章的标签。在属性名后加 ? 表示可选:
// 可选属性:在属性名后加 ?
interface Article {
title: string;
author?: string; // 可选,可以没有
tags?: string[]; // 可选
}
const a1: Article = { title: "标题" }; // 合法
const a2: Article = { title: "标题", author: "小明" }; // 也合法
// 注意:访问可选属性时,值可能是 undefined
const article: Article = { title: "t" };
console.log(article.author.length);
// ❌ TS 提醒:author 可能是 undefined
// 正确做法:先判空或用可选链
console.log(article.author?.length); // undefined(不报错)注意一个重要细节:访问可选属性时,TS 知道它可能是 undefined,会强制你先处理空值。用可选链 ?. 是最简洁的写法。这一点能挡住大量"undefined is not a function"的经典 bug。
3. 只读属性:readonly
有些字段创建后就不该再改(比如 id、创建时间)。用 readonly 修饰,赋值后任何修改都会报错:
// 只读属性:readonly 修饰,赋值后不能再改
interface Point {
readonly x: number;
readonly y: number;
}
const p: Point = { x: 1, y: 2 };
p.x = 3;
// ❌ 报错:无法分配到 "x",因为它是只读属性
// readonly 只在编译期检查,运行时并不真正阻止
// (和 const 类似,但 const 作用于变量,readonly 作用于属性)4. 描述函数类型
interface 不只能描述对象,还能描述函数的签名(参数和返回值)。不过函数类型更多用 type 别名写(下一章讲),这里了解即可:
// 用 interface 描述函数类型
interface Greet {
(name: string, age: number): string;
}
// 等价于 type 形式: type Greet = (name: string, age: number) => string
const greet: Greet = (name, age) => {
return `你好 ${name}, ${age} 岁`;
};
// 注意:参数 name/age 的类型由 interface 推断,不用再写
// 函数类型的 interface 不算常用,更多用 type 别名(下一章)5. 接口继承:extends
接口可以继承其他接口,复用已有定义。interface B extends A 表示 B 拥有 A 的全部字段,再加自己的:
// 接口可以继承(扩展)其他接口
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string; // Dog 拥有 name + breed
}
const d: Dog = { name: "旺财", breed: "金毛" };
// 一个接口可以继承多个接口(多继承)
interface Barker {
bark(): void;
}
interface Dog2 extends Animal, Barker {
breed: string;
}
// 接口还能"合并"(同名声明会自动合并字段)
interface Window { myProp: string; } // 给浏览器 Window 加自定义属性接口还能多继承(用逗号分隔),并且同名 interface 会自动合并字段——后者常用于给全局类型(如 Window)扩展自定义属性。
6. 索引签名:动态字段名
有时对象的字段名是不固定的(比如一个字典)。这时用索引签名:
7. 命名规范
- 接口名用大驼峰:
User、TodoItem、ApiResponse。 - 不加
I前缀:写User而不是IUser(这是 TS 社区的约定,和 Java/C# 不同)。 - 接口通常表示"名词"(数据形状),函数类型可以用
Handler、Callback这类词。
小结
interface 是 TS 描述对象形状的标准工具:必填属性直接写、可选加 ?、只读加 readonly、用 extends 继承。下一篇我们讲它的"兄弟"——类型别名 type,以及两者该怎么选。
← 上一篇 TypeScript 基础类型
下一篇 TypeScript 类型别名 →