TypeScript - Objects
TypeScript - Objects
Section titled “TypeScript - Objects”Objects are fundamental in JavaScript and TypeScript for grouping related data and functionality. They represent collections of key-value pairs, where keys are typically strings (or Symbols) and values can be anything: primitives (strings, numbers, booleans), functions (methods), arrays, or even other objects.
Creating Objects: Object Literals
Section titled “Creating Objects: Object Literals”The most common way to create objects is using object literal syntax {}.
// Object literal syntaxconst car = { make: "Toyota", model: "Camry", year: 2022, start: function() { // Method using traditional function syntax console.log(`Starting the ${this.make} ${this.model}...`); }, stop() { // Shorthand method syntax (ES6) console.log(`Stopping the ${this.make} ${this.model}.`); }, features: ["Air Conditioning", "Cruise Control"] // Value can be an array};
// Accessing properties using dot notationconsole.log(car.make); // Output: Toyotaconsole.log(car.year); // Output: 2202
// Accessing properties using bracket notation (useful for dynamic keys)const propertyName = "model";console.log(car[propertyName]); // Output: Camry
// Calling methodscar.start();car.stop();
console.log(car.features[0]); // Output: Air ConditioningTyping Objects in TypeScript
Section titled “Typing Objects in TypeScript”TypeScript allows you to define the shape or structure of objects, ensuring type safety when accessing properties or methods. There are several ways to type objects:
1. Type Inference
Section titled “1. Type Inference”When you create an object literal and assign it to a variable, TypeScript infers the types of its properties.
const inferredUser = { id: 101, username: "alice", isActive: true};
// TypeScript infers the type as: { id: number; username: string; isActive: boolean; }
console.log(inferredUser.username.toUpperCase()); // OK// inferredUser.id = "user-101"; // Error: Type 'string' is not assignable to type 'number'.2. Interface
Section titled “2. Interface”Using an interface is a common and idiomatic way to define the structure of an object explicitly.
interface Product { readonly sku: string; name: string; price: number; description?: string; // Optional property display(): void;}
const book: Product = { sku: "BK-123", name: "The TypeScript Handbook", price: 29.99, // description is optional display() { console.log(`${this.name} ($${this.price}) - SKU: ${this.sku}`); }};
book.display();// book.sku = "BK-456"; // Error: Cannot assign to 'sku' because it is a read-only property.3. Type Alias
Section titled “3. Type Alias”Using a type alias provides another way to define object shapes.
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. Anonymous Object Type Literals
Section titled “4. Anonymous Object Type Literals”You can define the shape directly in type annotations, often used for function parameters or return types when a reusable interface/type isn’t needed.
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 }); // Error: Object literal may only specify known properties...Objects as Function Parameters
Section titled “Objects as Function Parameters”Passing objects as parameters is very common. Use interfaces, type aliases, or anonymous types to define the expected structure of the parameter object.
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);Structural Typing (Duck Typing)
Section titled “Structural Typing (Duck Typing)”TypeScript uses a structural type system. This means that if an object has at least the properties and methods required by a type (like an interface), TypeScript considers it compatible with that type, regardless of whether it explicitly implements the interface. This is often called “duck typing”.
“If it walks like a duck and quacks like a duck, then it must be a duck.”
interface Named { name: string;}
let obj1 = { name: "My Object", value: 10 }; // Has 'name' propertylet obj2 = { title: "Another Object", name: "Named Item" }; // Has 'name' propertylet obj3 = { id: 123 }; // Does NOT have 'name' property
function printName(item: Named): void { console.log(`Name: ${item.name}`);}
printName(obj1); // OK - obj1 has a 'name: string' propertyprintName(obj2); // OK - obj2 has a 'name: string' property// printName(obj3); // Error: Argument of type '{ id: number; }' is not assignable to parameter of type 'Named'. Property 'name' is missing...This flexibility allows interoperability between different object structures as long as they share the required shape.