讲解
对象类型用花括号描述一个对象应该有哪些属性、各是什么类型:{ name: string; age: number }。属性默认必填,加问号变成可选(age?: number),读取可选属性时类型自动带上 undefined,必须处理空值情况。属性前加 readonly 则禁止重新赋值(只约束引用层面的重新赋值,嵌套对象的内部属性默认不管,需要逐层标注)。
当同一个对象形状被反复使用,内联写太啰嗦,这时用类型别名(type)给它起名字:type User = { name: string; age: number }。类型别名不是新类型,只是现有类型的名字,编译器在所有检查中把它和被命名的类型视为同一个东西。别名可以命名任何类型——对象、联合、函数、元组,是 TypeScript 里使用频率最高的工具之一。
对象类型还有一个「索引签名」语法 { [key: string]: number },表示「任意字符串键,值都是 number」,适合字典、映射表这类键名不确定的结构。索引签名和普通属性可以共存,但普通属性的类型必须兼容索引签名声明的值类型。
示例
内联对象类型与可选、只读属性:
function printBook(book: { title: string; author: string; year?: number }): void {
const yearText = book.year === undefined ? "年份不详" : `${book.year} 年`;
console.log(`《${book.title}》${book.author},${yearText}`);
}
printBook({ title: "活着", author: "余华", year: 1993 });
printBook({ title: "佚名笔记", author: "不详" });
类型别名复用形状:
type User = {
readonly id: number;
name: string;
email?: string;
};
function greet(user: User): string {
return `你好,${user.name}`;
}
const u: User = { id: 1, name: "小林" };
// u.id = 2; // 若取消注释:readonly 属性不能重新赋值
console.log(greet(u));
索引签名做字典:
type PriceTable = { [product: string]: number };
const prices: PriceTable = { 键盘: 299, 鼠标: 99 };
prices["显示器"] = 1299;
for (const [name, price] of Object.entries(prices)) {
console.log(`${name}:¥${price}`);
}
常见坑
- 多余属性检查只对字面量生效:直接把 { a: 1, b: 2 } 传给只要 { a: number } 的参数会因属性 b 报错;但先把字面量存进变量再传就不报。这是刻意设计,不是 bug。
- 误以为可选属性能省掉 undefined 处理:obj.year?.toFixed() 或先判空,二选一,不能当作必有值直接用。
- 以为 readonly 是深只读:readonly 只管当前层的重新赋值,嵌套对象照改不误;需要深只读时用工具类型或逐层标注。
- 索引签名值类型太宽:[key: string]: any 等于放弃所有属性的检查,尽量收窄到真实值类型的联合。
小结
对象类型描述属性形状,? 表可选、readonly 表只读;type 别名给类型起名,可复用任何类型;索引签名处理键名不定的字典。下一章的 interface 与对象类型高度相似,我们对比着讲。