TypeScript - 对象
TypeScript - 对象
Section titled “TypeScript - 对象”对象 (Objects) 是 JavaScript 和 TypeScript 中用于组织相关数据和功能的基石。它们表示键值对 (key-value pairs) 的集合,其中键 (keys) 通常是字符串 (strings)(或 Symbol),值 (values) 可以是任何类型:基本类型 (primitives)(字符串、数字、布尔值)、函数(方法 methods)、数组,甚至其他对象。
创建对象:对象字面量
Section titled “创建对象:对象字面量”创建对象最常用的方式是使用对象字面量 (object literal) 语法 {}。
// 对象字面量语法const car = { make: "Toyota", model: "Camry", year: 2022, start: function() { // 使用传统函数语法的方法 console.log(`Starting the ${this.make} ${this.model}...`); }, stop() { // 简写方法语法 (ES6) console.log(`Stopping the ${this.make} ${this.model}.`); }, features: ["Air Conditioning", "Cruise Control"] // 值可以是数组};
// 使用点符号访问属性console.log(car.make); // Output: Toyotaconsole.log(car.year); // Output: 2202
// 使用方括号符号访问属性(适用于动态键)const propertyName = "model";console.log(car[propertyName]); // Output: Camry
// 调用方法car.start();car.stop();
console.log(car.features[0]); // Output: Air Conditioning在 TypeScript 中为对象定义类型
Section titled “在 TypeScript 中为对象定义类型”TypeScript 允许你定义对象的形状或结构,确保在访问属性或方法时具有类型安全性 (type safety)。有几种为对象定义类型的方式:
1. 类型推断
Section titled “1. 类型推断”当你创建一个对象字面量并将其赋值给一个变量时,TypeScript 会推断 (infer) 其属性的类型。
const inferredUser = { id: 101, username: "alice", isActive: true};
// TypeScript 推断出的类型为: { id: number; username: string; isActive: boolean; }
console.log(inferredUser.username.toUpperCase()); // 正确// inferredUser.id = "user-101"; // 错误: 类型 'string' 不能赋值给类型 'number'。2. 接口 (Interface)
Section titled “2. 接口 (Interface)”使用 interface 是定义对象结构的常见且惯用的方式。
interface Product { readonly sku: string; name: string; price: number; description?: string; // 可选属性 display(): void;}
const book: Product = { sku: "BK-123", name: "The TypeScript Handbook", price: 29.99, // description 是可选的 display() { console.log(`${this.name} ($${this.price}) - SKU: ${this.sku}`); }};
book.display();// book.sku = "BK-456"; // 错误: 无法赋值到 'sku',因为它是一个只读属性。3. 类型别名 (Type Alias)
Section titled “3. 类型别名 (Type Alias)”使用 type 别名是另一种定义对象形状的方式。
type Point = { x: number; y: number;};
const origin: Point = { x: 0, y: 0 };
function calculateDistance(p1: Point, p2: Point): number { const dx = p1.x - p2.x; const dy = p1.y - p2.y; return Math.sqrt(dx * dx + dy * dy);}
const point1: Point = { x: 3, y: 4 };console.log(`Distance from origin: ${calculateDistance(origin, point1)}`); // Output: 54. 匿名对象类型字面量
Section titled “4. 匿名对象类型字面量”你可以直接在类型注解 (type annotations) 中定义对象形状,这常用于函数参数或返回值类型,特别是不需要可复用的接口或类型时。
function processCoords(coords: { lat: number; lon: number }): void { console.log(`Latitude: ${coords.lat}, Longitude: ${coords.lon}`);}
processCoords({ lat: 40.7128, lon: -74.0060 });// processCoords({ latitude: 40.7, longitude: -74 }); // 错误: 对象字面量只能指定已知属性...对象作为函数参数
Section titled “对象作为函数参数”将对象作为参数传递非常常见。使用接口、类型别名或匿名类型来定义参数对象的预期结构。
interface UserProfile { userId: string; email: string; displayName?: string;}
function displayUserProfile(profile: UserProfile): void { console.log(`User ID: ${profile.userId}`); console.log(`Email: ${profile.email}`); if (profile.displayName) { console.log(`Display Name: ${profile.displayName}`); }}
const user: UserProfile = { userId: 'u-001', email: 'user@example.com', displayName: 'Test User' };const userWithoutDisplayName: UserProfile = { userId: 'u-002', email: 'another@example.com' };
displayUserProfile(user);displayUserProfile(userWithoutDisplayName);结构化类型系统(鸭子类型)
Section titled “结构化类型系统(鸭子类型)”TypeScript 使用结构化类型系统 (structural type system)。这意味着如果一个对象至少拥有某个类型(如接口)所要求的属性和方法,TypeScript 就认为它与该类型兼容,无论它是否显式地 implements 了该接口。这通常被称为“鸭子类型 (duck typing)”。
“如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子。”
interface Named { name: string;}
let obj1 = { name: "My Object", value: 10 }; // 拥有 'name' 属性let obj2 = { title: "Another Object", name: "Named Item" }; // 拥有 'name' 属性let obj3 = { id: 123 }; // 没有 'name' 属性
function printName(item: Named): void { console.log(`Name: ${item.name}`);}
printName(obj1); // 正确 - obj1 拥有 'name: string' 属性printName(obj2); // 正确 - obj2 拥有 'name: string' 属性// printName(obj3); // 错误: 类型 '{ id: number; }' 不能赋值给类型 'Named' 的参数。缺少属性 'name'...这种灵活性使得不同对象结构之间可以相互操作,只要它们共享所需的形状。