TypeScript Object Types
Defining and working with object structures
๐ฆ What are Object Types?
Object types define the structure of objects by specifying property names and their types. You can create inline object types or reusable type aliases and interfaces for consistent object shapes throughout your code.
// Object type definition
let user: { name: string; age: number };
user = { name: "Alice", age: 25 };
Output:
user: { name: "Alice", age: 25 }
Ways to Define Object Types
Inline Type
Define type directly
let user: { name: string };
user = { name: "Alice" };
Type Alias
Reusable type definition
type User = { name: string };
let user: User;
Interface
Extendable object shape
interface User {
name: string;
}
๐น Basic Object Types
Define object structure with property types:
// Inline object type
let person: { name: string; age: number; isStudent: boolean };
person = {
name: "Alice",
age: 25,
isStudent: true
};
console.log(person.name); // "Alice"
console.log(person.age); // 25
console.log(person.isStudent); // true
// โ Missing property
// person = { name: "Bob" }; // Error: Property 'age' is missing
// โ Wrong type
// person = { name: "Bob", age: "25", isStudent: true }; // Error
Output:
Alice
25
true
๐น Type Aliases
Create reusable object type definitions:
// Define a type alias
type User = {
name: string;
age: number;
email: string;
};
// Use the type multiple times
let user1: User = {
name: "Alice",
age: 25,
email: "[email protected]"
};
let user2: User = {
name: "Bob",
age: 30,
email: "[email protected]"
};
console.log(user1.name); // "Alice"
console.log(user2.name); // "Bob"
Output:
Alice
Bob
๐น Optional Properties
Make object properties optional with ?:
// Optional properties
type Product = {
name: string;
price: number;
description?: string; // Optional
inStock?: boolean; // Optional
};
// Valid without optional properties
let product1: Product = {
name: "Laptop",
price: 999
};
// Valid with optional properties
let product2: Product = {
name: "Mouse",
price: 25,
description: "Wireless mouse",
inStock: true
};
console.log(product1.name); // "Laptop"
console.log(product2.description); // "Wireless mouse"
Output:
Laptop
Wireless mouse
๐น Readonly Properties
Prevent property modifications with readonly:
// Readonly properties
type User = {
readonly id: number;
name: string;
readonly createdAt: Date;
};
let user: User = {
id: 12345,
name: "Alice",
createdAt: new Date()
};
// โ
Can modify regular properties
user.name = "Alice Smith";
// โ Cannot modify readonly properties
// user.id = 54321; // Error: Cannot assign to 'id' because it is a read-only property
console.log(user.name); // "Alice Smith"
console.log(user.id); // 12345
Output:
Alice Smith
12345
๐น Nested Objects
Objects can contain other objects:
// Nested object types
type Address = {
street: string;
city: string;
zipCode: string;
};
type Person = {
name: string;
age: number;
address: Address; // Nested object
};
let person: Person = {
name: "Alice",
age: 25,
address: {
street: "123 Main St",
city: "New York",
zipCode: "10001"
}
};
console.log(person.name); // "Alice"
console.log(person.address.city); // "New York"
console.log(person.address.zipCode); // "10001"
Output:
Alice
New York
10001
๐น Index Signatures
Allow dynamic property names:
// Index signature for dynamic properties
type StringDictionary = {
[key: string]: string;
};
let translations: StringDictionary = {
hello: "Hola",
goodbye: "Adiรณs",
thanks: "Gracias"
};
console.log(translations.hello); // "Hola"
console.log(translations.goodbye); // "Adiรณs"
// Add new properties dynamically
translations.welcome = "Bienvenido";
console.log(translations.welcome); // "Bienvenido"
// Number index signature
type NumberArray = {
[index: number]: string;
};
let colors: NumberArray = {
0: "red",
1: "green",
2: "blue"
};
console.log(colors[0]); // "red"
Output:
Hola
Adiรณs
Bienvenido
red
๐น Interfaces
Alternative way to define object types:
// Interface definition
interface User {
name: string;
age: number;
email: string;
}
let user: User = {
name: "Alice",
age: 25,
email: "[email protected]"
};
// Extending interfaces
interface Admin extends User {
role: string;
permissions: string[];
}
let admin: Admin = {
name: "Bob",
age: 30,
email: "[email protected]",
role: "Administrator",
permissions: ["read", "write", "delete"]
};
console.log(admin.name); // "Bob"
console.log(admin.role); // "Administrator"
console.log(admin.permissions); // ["read", "write", "delete"]
Output:
Bob
Administrator
["read", "write", "delete"]
๐น Practical Example
Building a user management system:
// Define types
type UserRole = "admin" | "user" | "guest";
type User = {
readonly id: number;
name: string;
email: string;
role: UserRole;
isActive: boolean;
lastLogin?: Date;
};
// Create users
let users: User[] = [
{
id: 1,
name: "Alice",
email: "[email protected]",
role: "admin",
isActive: true,
lastLogin: new Date()
},
{
id: 2,
name: "Bob",
email: "[email protected]",
role: "user",
isActive: true
}
];
// Function using object types
function displayUser(user: User): string {
return `${user.name} (${user.role}) - ${user.email}`;
}
console.log(displayUser(users[0])); // Alice (admin) - [email protected]
console.log(displayUser(users[1])); // Bob (user) - [email protected]
Output:
Alice (admin) - [email protected]
Bob (user) - [email protected]
๐น Type vs Interface
Type Alias:
- Can represent any type (primitives, unions, tuples)
- Cannot be reopened to add properties
- Better for unions and complex types
Interface:
- Only for object shapes
- Can be extended and merged
- Better for object-oriented patterns
- Slightly better error messages
๐ก Tip:
Use interfaces for objects that might be extended. Use type aliases for everything else.