对象类型与接口 interface
本节目标
- 用「内联对象类型」和
interface描述对象结构 - 区分
interface与type的取舍 - 掌握「可选属性
?」「只读属性readonly」
描述一个对象长什么样,最直观是「内联写法」:
// 运行环境:Node.js 16+ + typescript;类型检查 npx tsc --noEmit ts-l5.ts
// 内联对象类型:直接写在注解位置
function printUser(user: { name: string; age: number }): void {
console.log(`${user.name} / ${user.age}`)
}
printUser({ name: 'Laowen', age: 30 })但当结构要复用时,用 interface 给它起个名字:
// 用 interface 定义「用户」结构,全项目复用
interface User {
name: string
age: number
email?: string // ? 表示可选:可以有也可以没有
readonly id: number // readonly:创建后不能改
}
const u: User = { name: 'A', age: 20, id: 1 }
// u.id = 2 // ❌ Cannot assign to 'id' because it is read-only
// const u2: User = { name: 'B', id: 2 } // ❌ 缺少必填的 age
function greet(user: User): string {
return `Hi ${user.name}`
}interface 和 type 大部分场景等价,区别在:interface 可以「声明合并」(同名的 interface 会自动合并字段),type 更灵活(能描述联合、元组、基础类型别名)。经验法则:描述「对象/类结构」优先 interface;做类型运算(联合、交叉、映射)用 type。
// type 能做到 interface 做不到的:
type ID = string | number // 联合
type Point = { x: number; y: number }
type Point3D = Point & { z: number } // 交叉,合并出三维点名词解释
接口(interface):给「对象的形状」起的名字。它只描述「这个对象应该有哪些字段、各是什么类型」,不关心值从哪来。你可以把它理解成「对象的体检表」——TS 拿它去核对每个对象合不合格。
可选属性(?)/ 只读属性(readonly):age?: number 表示「这个字段可能缺席」,访问前要判空;readonly id 表示「出生时定好、之后不能再改」,编译期保护你不被意外覆盖。它们都是从「代码意图」层面帮你少犯错。
课后练习
练习 1:定义一个 Book 接口,含 title(必填 string)、author(必填 string)、year(可选 number),并写一个函数返回书名。
答案:
interface Book { title: string author: string year?: number } function getTitle(b: Book): string { return b.title }
练习 2:interface 和 type 在描述对象时最大的「能力差异」是什么?
答案:
interface支持同名声明合并(多次声明同名字段会合并),适合被第三方扩展(如给Window加字段);type能做联合、交叉、映射类型等类型运算,表达能力更强。描述纯对象结构时二者几乎等价。
总结
我的观点:interface 和 type 之争在团队里常常被过度讨论,其实90% 的场景二者随便选都不会错。我个人的默认是——凡是「描述一个东西长什么样」(对象、类)就用 interface,因为可读性更好、能被合并;凡是「做类型层面的计算」(联合、交叉、提取)才用 type。比「选哪个」更重要的是:给复用三次以上的结构起名字,别让 { name: string; age: number } 这种内联类型在代码里复制粘贴十遍——那才是真正拖慢维护的坏习惯。