介绍
TS 中 {} 代表 对象类型字面量,区别于 JS 普通对象,用来 约束对象的结构:
- 属性名
- 属性类型
- 可选属性
- 只读属性
- 方法
- 索引签名等
区分 JS、TS大括号对象
const obj = {}→ JS 对象实例type T = {}→ TS对象类型约束
应用场景
定义简单实体结构(最常用)。比如:AJAX接口返回数据、表单、简单模型,一次性定义数据结构
函数参数 / 返回值约束
配置对象、选项参数
定义方式1-type定义
使用 type 定义对象结构
type:TS 用来 创建自定义类型别名 的语法。User:自定义类型名称(首字母大写,约定俗成)。=后面大括号{ ... }→【对象字面量类型】
定义对象结构
// 定义类型别名 User
type User = {
id: number;
name: string;
age?: number; // 可选属性
};
解释: id: number;
必填属性:对象必须有 id,值必须是数字,不能省略。
解释:name: string;
必填属性:必须有 name,值为字符串,不能省略。
解释 age?: number;
- 对象可以写 age,也可以不写 age;
- 如果写上 age,值必须是 number;
- 不写 age 等价于 age: number | undefined。
定义对象,有age
const u1: User = {
id: 1,
name: "小明",
age: 18
}
定义对象,没有age(允许,因为age是可选)
const u2: User = {
id: 2,
name: "小红"
}
错误定义对象
// 缺少必填 name,报错
const u3: User = { id: 3 }
// id 传字符串,类型不匹配,报错
const u4: User = { id: "4", name: "小李" }
定义方式2-interface
描述一个对象必须具备什么结构。
定义接口
interface User {
id: number;
name: string;
age?: number; // 可选属性
}
解释: id: number;
必填属性:对象必须有 id,值必须是数字,不能省略。
解释:name: string;
必填属性:必须有 name,值为字符串,不能省略。
解释 age?: number;
- 对象可以写 age,也可以不写 age;
- 如果写上 age,值必须是 number;
- 不写 age 等价于 age: number | undefined。
定义对象,有age
const u1: User = {
id: 1,
name: "小明",
age: 18
}
定义对象,没有age(允许,因为age是可选)
const u2: User = {
id: 2,
name: "小红"
}
错误定义对象
// 缺少必填 name,报错
const u3: User = { id: 3 }
// id 传字符串,类型不匹配,报错
const u4: User = { id: "4", name: "小李" }
两种定义方式的选择
定义大括号对象,一般情况,type 与 interface 区别不大
优先选择 type(90% 前端业务,接口返回数据、表单)
- 定义后端返回 DTO、列表数据、普通对象
- 需要用到联合类型 |、多种状态分支
- 类型不需要外部扩展、一次性结构
- 需要组合多个类型(交叉 &)
优先选择 interface
- 需要声明合并(扩充全局类型、框架类型拓展)
- 编写类 class implements 实现规范
- 设计通用对外暴露的公共 API、组件约束
常见用法
1. 可选属性 ?
属性可以不提供,值允许 undefined
type User = {
id: number;
email?: string; // 可选
}
const u1: User = { id: 1 };
const u2: User = { id: 2, email: "a@qq.com" };
2. 只读属性 readonly
属性初始化后不能修改,仅约束类型层面
type User = {
readonly id: number;
name: string;
}
const u: User = { id: 1, name: "test" };
u.id = 2; // ❌ 报错,只读无法修改
u.name = "new"; // ✅
注意:
readonly只限制属性重新赋值,不限制对象内部可变数据type Data = { readonly list: number[] } const d: Data = { list: [1,2] }; d.list.push(3); // ✅ 正常,数组引用没变
3. 对象内定义方法
两种写法等价
type Person = {
// 写法1:函数属性
sayHi: () => void;
// 写法2:方法简写(推荐)
greet(name: string): string;
}
const p: Person = {
sayHi() {
console.log("hi");
},
greet(name) {
return `Hello ${name}`;
}
}
4. 空对象类型 {}
type EmptyObj = {};
⚠️ 重大误区:{} 不是“空对象,不能有任何属性”{} 代表:可以拥有任意属性,但是不能使用 null / undefined
let o: {};
o = 1; // ✅
o = "abc"; // ✅
o = {}; // ✅
o = null; // ❌
如果你想要完全空对象,禁止任何属性:
type StrictEmpty = Record<string, never>
const e: StrictEmpty = {};
e.xxx = 1; // ❌ 报错
5. 属性修饰组合
type T = {
readonly uid: number;
desc?: string | null;
}
常见坑 & 易错点
坑1:字面量对象多余属性直接赋值报错
type User = { id: number }
const u: User = { id: 1, name: "xx" } // ❌ 对象字面量直接赋值会校验多余属性
绕过方案(不推荐,尽量规范):
const temp = { id:1, name:"xx" }
const u: User = temp; // ✅ 变量中转不再严格校验额外属性
坑2:readonly 仅类型层面,编译后消失
TS 编译成 JS 没有只读限制,运行时依然可以修改。如需运行时保护要用 Object.freeze
坑3:区分 {}、object、Record<string,any>
{}:允许除 null/undefined 以外所有值(原始值、对象都行)object:只允许引用类型(数组、对象,不能是 number/string 原始值)Record<string, any>:键为字符串的普通对象
let a: {};
let b: object;
a = 1; // ✅
b = 1; // ❌