TypeScript 对象

TypeScript 中的对象详解

在 TypeScript 中,对象 是最常见的数据结构之一。TypeScript 通过强大的类型系统来描述对象的形状(shape),确保对象属性存在、类型正确,从而大幅减少运行时错误。

1. 对象字面量与类型推断

let user = {
  name: "Alice",
  age: 30,
  isAdmin: true
};

// 类型推断为:{ name: string; age: number; isAdmin: boolean; }
user.name = "Bob";      // OK
// user.age = "30";     // 错误:类型不匹配
// user.role = "admin"; // 错误:对象上不存在 role 属性

2. 使用接口(interface)定义对象类型(推荐)

interface User {
  name: string;
  age: number;
  isAdmin?: boolean;      // 可选属性
  readonly id: number;    // 只读属性
}

let admin: User = {
  name: "Eve",
  age: 28,
  id: 1
  // isAdmin 可省略
};

// admin.id = 2;        // 错误:只读属性
admin.age = 29;         // OK

3. 使用类型别名(type)定义对象类型

type Point = {
  x: number;
  y: number;
  z?: number;             // 可选
};

let origin: Point = { x: 0, y: 0 };
// origin.z = undefined; // OK,可选属性可为 undefined

4. 匿名对象类型

直接在变量声明时定义(适合临时使用):

let config: {
  apiUrl: string;
  timeout: number;
  readonly debug: boolean;
} = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  debug: true
};

5. 索引签名(Index Signatures)—— 动态属性

当对象属性名不确定时使用:

interface StringMap {
  [key: string]: string;  // 任意 string 键,值必须是 string
}

let headers: StringMap = {
  "Content-Type": "application/json",
  "Authorization": "Bearer token123"
};

headers["X-Custom"] = "value";  // OK
// headers.age = 30;           // 错误:值必须是 string

也可以限制键为 number:

interface NumberArray {
  [index: number]: string;  // 如数组,但值必须是 string
}

6. 额外属性检查(Excess Property Checks)

TypeScript 对对象字面量有严格检查:

interface Person {
  name: string;
  age: number;
}

let p: Person = {
  name: "Tom",
  age: 25,
  role: "admin"  // 错误:role 不存在于 Person 接口
};

// 但通过变量赋值可绕过(结构化类型系统):
let extra = { name: "Tom", age: 25, role: "admin" };
let p2: Person = extra;  // OK,多余属性被允许

7. 对象展开与合并

let defaults = { timeout: 3000, retries: 3 };
let config = { ...defaults, timeout: 5000 };  // timeout 被覆盖

// 类型:{ timeout: number; retries: number; }

8. 内置工具类型(Utility Types)操作对象

TypeScript 提供许多实用类型来变换对象类型:

工具类型作用示例
Partial<T>所有属性变为可选Partial<User> → name?, age?, isAdmin?
Required<T>所有属性变为必选Required<User>
Readonly<T>所有属性变为只读Readonly<User>
Pick<T, K>挑选指定属性Pick<User, "name" | "age">
Omit<T, K>排除指定属性Omit<User, "id">
Record<K, T>创建键为 K、值为 T 的对象类型Record<string, number>

示例:

type UserUpdate = Partial<User>;  // 更新时所有字段可选
let update: UserUpdate = { name: "New Name" };  // OK,只改 name

type UserBasic = Pick<User, "name" | "age">;
let basic: UserBasic = { name: "Alice", age: 30 };

9. 对象 vs Map

场景推荐使用
键为字符串,结构固定对象 + interface
键为任意类型(对象、Symbol)Map
需要动态添加属性对象 + 索引签名 或 Map

10. 最佳实践建议

建议说明
始终为对象定义接口或 type提升可读性和安全性
可选属性用 ?,只读用 readonly明确意图
动态对象用索引签名避免 any
使用工具类型改造对象如 Partial 用于更新函数参数
避免 any 类型对象用 unknown 或具体接口替代
开启 strict 模式包括 noImplicitAnystrictNullChecks

小结:对象类型常见写法速查

场景推荐写法
固定结构对象interface User { name: string; age: number; }
可选/只读属性isActive?: boolean; readonly id: number;
动态键对象[key: string]: string;
更新对象Partial<User>
只取部分字段Pick<User, "name" | "age">
排除字段Omit<User, "password">

对象是 TypeScript 中最核心的数据载体,通过接口、工具类型和类型推断的结合,能实现高度类型安全的代码。

如果您想深入某个部分(如嵌套对象对象解构与类型对象合并的高级类型、或实际项目中的对象设计),请告诉我!

文章已创建 3383

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部