Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /Typescript
  4. /Objects Type Aliases
Your Progress0%
0 of 30 completed

TypeScript Topics

Getting Started

  • What is TypeScript?
  • TypeScript vs JavaScript
  • Setting Up TypeScript
  • Your First TypeScript Program

Basic Types

  • Primitive Types
  • Arrays and Tuples
  • Objects and Type Aliases
  • Enums
  • Any, Unknown, and Never

Functions & Interfaces

  • Function Types and Signatures
  • Interfaces
  • Optional and Default Parameters
  • Function Overloading

Advanced Types

  • Union and Intersection Types
  • Type Guards and Narrowing
  • Literal Types
  • Type Assertions and Casting

Generics

  • Introduction to Generics
  • Generic Constraints
  • Utility Types

Classes & OOP

  • Classes and Constructors
  • Access Modifiers
  • Inheritance and Polymorphism
  • Abstract Classes and Interfaces

Practical TypeScript

  • Working with Modules
  • TypeScript with React
  • Async/Await and Promises
  • Working with APIs and JSON
  • Type Declarations and DefinitelyTyped
  • TypeScript Best Practices

Objects and Type Aliases

Defining object shapes and creating reusable types

Objects are fundamental to JavaScript and TypeScript. Unlike primitive types that hold single values, objects can hold multiple related values as properties. TypeScript allows you to define the exact shape of objects and create reusable type definitions. Let's master object types and type aliases!

Object Types in TypeScript

In TypeScript, you can specify the exact structure an object should have—what properties it contains and what type each property is.

Inline Object Types

inline-objects.ts
// Inline object type annotation
let user: { name: string; age: number; email: string } = {
  name: "Yusuf Ibrahim",
  age: 25,
  email: "yusuf@example.com"
};

// Function with inline object parameter type
function greetUser(user: { name: string; age: number }): string {
  return `Hello, ${user.name}! You are ${user.age} years old.`;
}

// Using the function
let greeting = greetUser({ name: "Amina", age: 30 });
console.log(greeting);  // "Hello, Amina! You are 30 years old."

// Object with different property types
let product: {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
} = {
  id: 1,
  name: "Laptop",
  price: 250000,
  inStock: true
};

console.log(`${product.name}: ₦${product.price}`);

Inline object types work well for simple, one-time use cases, but they become unwieldy for complex objects or when you need to reuse the same type. That's where type aliases come in!

Type Aliases

Type aliases let you create a reusable name for any type. Use the type keyword to define them.

Basic Type Aliases

type-aliases-basic.ts
// Create a type alias for an object
type User = {
  name: string;
  age: number;
  email: string;
};

// Use the type alias
let user1: User = {
  name: "Yusuf Ibrahim",
  age: 25,
  email: "yusuf@example.com"
};

let user2: User = {
  name: "Amina Hassan",
  age: 30,
  email: "amina@example.com"
};

// Function using type alias
function displayUser(user: User): void {
  console.log(`Name: ${user.name}`);
  console.log(`Age: ${user.age}`);
  console.log(`Email: ${user.email}`);
}

displayUser(user1);

// Type alias for primitive types (less common but possible)
type ID = number;
type Email = string;

let userId: ID = 12345;
let userEmail: Email = "user@example.com";

Type Aliases for Complex Objects

complex-type-aliases.ts
// Product type
type Product = {
  id: number;
  name: string;
  description: string;
  price: number;
  category: string;
  inStock: boolean;
  tags: string[];
};

// Order type
type Order = {
  orderId: number;
  customerId: number;
  products: Product[];
  totalAmount: number;
  status: string;
  orderDate: Date;
};

// Customer type
type Customer = {
  id: number;
  name: string;
  email: string;
  phone: string;
  address: {
    street: string;
    city: string;
    state: string;
    zipCode: string;
  };
};

// Using the types
let laptop: Product = {
  id: 1,
  name: "Dell XPS 15",
  description: "High-performance laptop",
  price: 450000,
  category: "Electronics",
  inStock: true,
  tags: ["laptop", "computer", "dell"]
};

let customer: Customer = {
  id: 101,
  name: "Yusuf Ibrahim",
  email: "yusuf@example.com",
  phone: "+234-803-123-4567",
  address: {
    street: "123 Main Street",
    city: "Lagos",
    state: "Lagos State",
    zipCode: "100001"
  }
};

console.log(`Customer: ${customer.name} from ${customer.address.city}`);

User Type Structure

▼
Usertype alias

Complete user profile structure

type User = {
  id: number;
  name: string;
  email: string;
  age?: number;
  readonly createdAt: Date;
}
idnumber

Unique identifier (required)

namestring

User's full name (required)

emailstring

User's email address (required)

agenumber | undefined

User's age (optional - may not be provided)

createdAtDate (readonly)

Account creation date (cannot be modified)

Optional Properties

Sometimes object properties are optional—they may or may not be present. Use ? to mark properties as optional.

optional-properties.ts
// Type with optional properties
type User = {
  id: number;
  name: string;
  email: string;
  age?: number;          // Optional
  phone?: string;        // Optional
  address?: string;      // Optional
};

// Valid: All required properties present
let user1: User = {
  id: 1,
  name: "Yusuf Ibrahim",
  email: "yusuf@example.com"
};

// Valid: Includes optional properties
let user2: User = {
  id: 2,
  name: "Amina Hassan",
  email: "amina@example.com",
  age: 30,
  phone: "+234-803-123-4567"
};

// Valid: All properties including optional ones
let user3: User = {
  id: 3,
  name: "Chidi Okafor",
  email: "chidi@example.com",
  age: 28,
  phone: "+234-805-987-6543",
  address: "Lagos, Africa"
};

// Function handling optional properties
function displayUserInfo(user: User): void {
  console.log(`Name: ${user.name}`);
  console.log(`Email: ${user.email}`);
  
  // Check if optional property exists
  if (user.age !== undefined) {
    console.log(`Age: ${user.age}`);
  }
  
  // Using optional chaining
  console.log(`Phone: ${user.phone ?? "Not provided"}`);
  console.log(`Address: ${user.address ?? "Not provided"}`);
}

displayUserInfo(user1);
displayUserInfo(user2);

💡 Optional vs Undefined

property? is equivalent to property: Type | undefined. Both mean the property may not be present. Use optional properties (?) for better readability.

Default Values with Optional Properties

optional-defaults.ts
type Config = {
  host: string;
  port?: number;
  secure?: boolean;
  timeout?: number;
};

function createConnection(config: Config): void {
  // Provide default values for optional properties
  const port = config.port ?? 8080;
  const secure = config.secure ?? false;
  const timeout = config.timeout ?? 30000;
  
  console.log(`Connecting to ${config.host}:${port}`);
  console.log(`Secure: ${secure}`);
  console.log(`Timeout: ${timeout}ms`);
}

// Only required property
createConnection({ host: "localhost" });
// Output:
// Connecting to localhost:8080
// Secure: false
// Timeout: 30000ms

// With some optional properties
createConnection({
  host: "api.example.com",
  port: 443,
  secure: true
});
// Output:
// Connecting to api.example.com:443
// Secure: true
// Timeout: 30000ms

Readonly Properties

Use readonly to prevent properties from being modified after object creation.

readonly-properties.ts
// Type with readonly properties
type User = {
  readonly id: number;           // Cannot be changed
  readonly createdAt: Date;      // Cannot be changed
  name: string;                  // Can be changed
  email: string;                 // Can be changed
};

let user: User = {
  id: 1,
  createdAt: new Date(),
  name: "Yusuf Ibrahim",
  email: "yusuf@example.com"
};

// These are allowed
user.name = "Yusuf A. Ibrahim";    // ✅ Works
user.email = "yusuf.new@example.com";  // ✅ Works

// These cause errors
// user.id = 2;                    // ❌ Error: Cannot assign to 'id'
// user.createdAt = new Date();    // ❌ Error: Cannot assign to 'createdAt'

console.log(`User ID: ${user.id} (readonly)`);
console.log(`Name: ${user.name} (can be changed)`);

Readonly in Nested Objects

nested-readonly.ts
type Article = {
  readonly id: number;
  readonly author: {
    readonly name: string;
    readonly email: string;
  };
  title: string;
  content: string;
};

let article: Article = {
  id: 1,
  author: {
    name: "Yusuf Ibrahim",
    email: "yusuf@example.com"
  },
  title: "TypeScript Guide",
  content: "Learning TypeScript..."
};

// Can modify non-readonly properties
article.title = "Complete TypeScript Guide";  // ✅ Works
article.content = "Updated content...";       // ✅ Works

// Cannot modify readonly properties
// article.id = 2;                     // ❌ Error
// article.author.name = "New Name";   // ❌ Error
// article.author.email = "new@example.com";  // ❌ Error

// Can reassign the entire object
article = {
  id: 2,  // Different ID allowed when creating new object
  author: {
    name: "Amina Hassan",
    email: "amina@example.com"
  },
  title: "New Article",
  content: "New content..."
};

🔒 When to Use Readonly

  • Database IDs that should never change
  • Timestamps (createdAt, updatedAt)
  • Configuration values that are set once
  • Any property that represents immutable data

Nested Objects

Objects can contain other objects as properties, creating nested structures.

nested-objects.ts
// Type with nested objects
type Address = {
  street: string;
  city: string;
  state: string;
  country: string;
  zipCode: string;
};

type Company = {
  name: string;
  industry: string;
  founded: number;
};

type Employee = {
  id: number;
  name: string;
  email: string;
  address: Address;      // Nested object
  company: Company;      // Nested object
  salary: number;
};

// Creating an object with nested structure
let employee: Employee = {
  id: 1,
  name: "Yusuf Ibrahim",
  email: "yusuf@company.com",
  address: {
    street: "123 Main Street",
    city: "Lagos",
    state: "Lagos State",
    country: "Nigeria",
    zipCode: "100001"
  },
  company: {
    name: "TechCorp Africa",
    industry: "Technology",
    founded: 2015
  },
  salary: 500000
};

// Accessing nested properties
console.log(`Employee: ${employee.name}`);
console.log(`City: ${employee.address.city}`);
console.log(`Company: ${employee.company.name}`);
console.log(`Founded: ${employee.company.founded}`);

// Function working with nested objects
function displayEmployeeLocation(emp: Employee): string {
  return `${emp.name} works in ${emp.address.city}, ${emp.address.country}`;
}

console.log(displayEmployeeLocation(employee));

Inline vs Separate Type Definitions

inline-vs-separate.ts
// Option 1: Inline nested object type
type Product1 = {
  id: number;
  name: string;
  vendor: {
    name: string;
    contact: string;
  };
};

// Option 2: Separate type definitions (better for reusability)
type Vendor = {
  name: string;
  contact: string;
};

type Product2 = {
  id: number;
  name: string;
  vendor: Vendor;  // Reusable type
};

// Now Vendor type can be used elsewhere
let vendor1: Vendor = {
  name: "TechSupplies Ltd",
  contact: "tech@supplies.com"
};

let vendor2: Vendor = {
  name: "ElectroMart",
  contact: "info@electromart.com"
};

let product: Product2 = {
  id: 1,
  name: "Laptop",
  vendor: vendor1
};

Objects with Methods

Objects can have methods (functions as properties).

object-methods.ts
// Type with method signatures
type Calculator = {
  value: number;
  add: (n: number) => number;
  subtract: (n: number) => number;
  multiply: (n: number) => number;
  divide: (n: number) => number;
  reset: () => void;
};

// Implementing the object
let calculator: Calculator = {
  value: 0,
  
  add(n: number): number {
    this.value += n;
    return this.value;
  },
  
  subtract(n: number): number {
    this.value -= n;
    return this.value;
  },
  
  multiply(n: number): number {
    this.value *= n;
    return this.value;
  },
  
  divide(n: number): number {
    if (n === 0) {
      throw new Error("Cannot divide by zero");
    }
    this.value /= n;
    return this.value;
  },
  
  reset(): void {
    this.value = 0;
  }
};

// Using the calculator
calculator.add(10);        // 10
calculator.multiply(5);    // 50
calculator.subtract(20);   // 30
console.log(`Result: ${calculator.value}`);  // 30

calculator.reset();
console.log(`After reset: ${calculator.value}`);  // 0

Alternative Method Syntax

method-syntax-alt.ts
// Type with different method syntax options
type Person = {
  name: string;
  
  // Method syntax 1: Property with function type
  greet1: (greeting: string) => string;
  
  // Method syntax 2: Method signature (preferred for object types)
  greet2(greeting: string): string;
};

let person: Person = {
  name: "Yusuf",
  
  greet1: function(greeting: string): string {
    return `${greeting}, I'm ${this.name}`;
  },
  
  greet2(greeting: string): string {
    return `${greeting}, I'm ${this.name}`;
  }
};

console.log(person.greet1("Hello"));  // "Hello, I'm Yusuf"
console.log(person.greet2("Hi"));     // "Hi, I'm Yusuf"

Index Signatures

Index signatures allow objects to have properties with dynamic names of a certain type.

index-signatures.ts
// Index signature: properties can have any string key
type Dictionary = {
  [key: string]: string;
};

let translations: Dictionary = {
  hello: "Sannu",
  goodbye: "Sai anjima",
  thank_you: "Na gode"
};

// Can add any string key
translations.yes = "Eh";
translations.no = "A'a";

console.log(translations.hello);      // "Sannu"
console.log(translations.thank_you);  // "Na gode"

// Index signature with number keys
type NumberDictionary = {
  [index: number]: string;
};

let days: NumberDictionary = {
  0: "Sunday",
  1: "Monday",
  2: "Tuesday",
  3: "Wednesday",
  4: "Thursday",
  5: "Friday",
  6: "Saturday"
};

console.log(days[0]);  // "Sunday"
console.log(days[5]);  // "Friday"

Combining Index Signatures with Known Properties

mixed-signatures.ts
// Type with specific properties AND index signature
type Config = {
  host: string;        // Required specific property
  port: number;        // Required specific property
  [key: string]: string | number;  // Additional dynamic properties
};

let serverConfig: Config = {
  host: "localhost",
  port: 8080,
  timeout: 30000,      // Additional property (number)
  maxConnections: 100, // Additional property (number)
  environment: "development"  // Additional property (string)
};

console.log(serverConfig.host);          // "localhost"
console.log(serverConfig.timeout);       // 30000
console.log(serverConfig.environment);   // "development"

// Practical example: API Response
type ApiResponse = {
  status: number;
  message: string;
  [key: string]: any;  // Allow any additional data
};

let response: ApiResponse = {
  status: 200,
  message: "Success",
  data: { id: 1, name: "User" },
  timestamp: new Date(),
  requestId: "abc-123"
};

Type Aliases vs Interfaces Preview

While we'll cover interfaces in detail in a later lesson, it's worth noting that type aliases and interfaces are similar for object types.

type-vs-interface.ts
// Using Type Alias
type UserType = {
  id: number;
  name: string;
  email: string;
};

// Using Interface (covered in detail later)
interface UserInterface {
  id: number;
  name: string;
  email: string;
}

// Both work similarly for objects
let user1: UserType = {
  id: 1,
  name: "Yusuf",
  email: "yusuf@example.com"
};

let user2: UserInterface = {
  id: 2,
  name: "Amina",
  email: "amina@example.com"
};

// Type aliases can do more than interfaces
type ID = number | string;  // Union types
type Callback = () => void;  // Function types
type StringArray = string[];  // Array types

// We'll learn when to use each in the Interfaces lesson!

For now, use type aliases for object types. We'll explore interfaces in depth in a future lesson and learn when to choose one over the other.

Practical Example: E-Commerce System

Let's build a complete type system for an e-commerce application:

ecommerce-types.ts
// Base types
type Product = {
  readonly id: number;
  name: string;
  description: string;
  price: number;
  category: string;
  inStock: boolean;
  images: string[];
  rating?: number;
};

type CartItem = {
  product: Product;
  quantity: number;
};

type Address = {
  street: string;
  city: string;
  state: string;
  zipCode: string;
};

type Customer = {
  readonly id: number;
  name: string;
  email: string;
  phone?: string;
  addresses: Address[];
  readonly registeredAt: Date;
};

type Order = {
  readonly id: number;
  readonly orderId: string;
  customer: Customer;
  items: CartItem[];
  shippingAddress: Address;
  totalAmount: number;
  status: "pending" | "processing" | "shipped" | "delivered";
  readonly createdAt: Date;
  deliveredAt?: Date;
};

// Sample data
const laptop: Product = {
  id: 1,
  name: "Dell XPS 15",
  description: "High-performance laptop for professionals",
  price: 450000,
  category: "Electronics",
  inStock: true,
  images: ["laptop1.jpg", "laptop2.jpg"],
  rating: 4.5
};

const customer: Customer = {
  id: 101,
  name: "Yusuf Ibrahim",
  email: "yusuf@example.com",
  phone: "+234-803-123-4567",
  addresses: [
    {
      street: "123 Main Street",
      city: "Lagos",
      state: "Lagos State",
      zipCode: "100001"
    }
  ],
  registeredAt: new Date("2024-01-15")
};

const order: Order = {
  id: 1001,
  orderId: "ORD-2024-1001",
  customer: customer,
  items: [
    {
      product: laptop,
      quantity: 1
    }
  ],
  shippingAddress: customer.addresses[0],
  totalAmount: 450000,
  status: "pending",
  createdAt: new Date()
};

// Helper functions
function calculateOrderTotal(items: CartItem[]): number {
  return items.reduce((total, item) => {
    return total + (item.product.price * item.quantity);
  }, 0);
}

function displayOrderSummary(order: Order): void {
  console.log(`Order ID: ${order.orderId}`);
  console.log(`Customer: ${order.customer.name}`);
  console.log(`Items:`);
  
  order.items.forEach(item => {
    console.log(`  - ${item.product.name} x ${item.quantity} = ₦${item.product.price * item.quantity}`);
  });
  
  console.log(`Total: ₦${order.totalAmount}`);
  console.log(`Status: ${order.status}`);
  console.log(`Shipping to: ${order.shippingAddress.city}, ${order.shippingAddress.state}`);
}

displayOrderSummary(order);

Test Your Knowledge

Type Safety Check

Which object assignment is valid?

type User = {
  name: string;
  age: number;
  email: string;
};

// Option A
const user1: User = { name: "Yusuf", age: 25 };

// Option B
const user2: User = { name: "Amina", age: 30, email: "amina@example.com" };

// Option C
const user3: User = { name: "Chidi", age: "28", email: "chidi@example.com" };

// Option D
const user4: User = { name: "Fatima", age: 22, email: "fatima@example.com", city: "Lagos" };

Common TypeScript Error

Code with Error
// Attempting to access non-existent property
type Product = {
  id: number;
  name: string;
  price: number;
};

const laptop: Product = {
  id: 1,
  name: "Dell Laptop",
  price: 250000
};

// Trying to access a property that doesn't exist
console.log(laptop.category);  // Error!
laptop.discount = 10;           // Error!

❌ Property 'category' does not exist on type 'Product'. Property 'discount' does not exist on type 'Product'.

What's Wrong?

TypeScript only allows you to access properties that are defined in the object's type. This prevents typos and ensures you're working with the expected structure.

Corrected Code
// Fix 1: Add property to type
type Product = {
  id: number;
  name: string;
  price: number;
  category?: string;    // Optional property
  discount?: number;    // Optional property
};

const laptop: Product = {
  id: 1,
  name: "Dell Laptop",
  price: 250000,
  category: "Electronics",
  discount: 10
};

// Fix 2: Use existing properties
console.log(laptop.name);   // ✅ Works
console.log(laptop.price);  // ✅ Works

Solution: Add the property to the type definition or use the correct property name

Best Practices

  1. Use type aliases for reusable object types
  2. Mark properties as readonly when they shouldn't change
  3. Use optional properties (?) for properties that may not exist
  4. Extract nested types into separate type aliases for reusability
  5. Use descriptive names for type aliases (PascalCase convention)
  6. Keep types close to where they're used in the code
  7. Use index signatures sparingly—prefer known properties when possible
  8. Document complex types with comments
best-practices-example.ts
// ✅ Good: Reusable, well-structured types

// Base types
type UUID = string;
type Timestamp = Date;

// Shared types
type Address = {
  street: string;
  city: string;
  state: string;
  zipCode: string;
};

// Main type with readonly and optional properties
type User = {
  readonly id: UUID;
  readonly createdAt: Timestamp;
  name: string;
  email: string;
  age?: number;              // Optional
  phone?: string;            // Optional
  address?: Address;         // Optional nested type
};

// Function with clear type usage
function createUser(
  name: string,
  email: string,
  address?: Address
): User {
  return {
    id: crypto.randomUUID(),
    createdAt: new Date(),
    name,
    email,
    address
  };
}

// ❌ Avoid: Inline types, hard to reuse
function badExample(
  user: {
    id: string;
    name: string;
    email: string;
    address: {
      street: string;
      city: string;
    };
  }
): void {
  // Inline type is hard to reuse and maintain
}

Key Takeaways

  • Objects in TypeScript have defined shapes with specific property types
  • Type aliases create reusable names for types using the type keyword
  • Optional properties use ? and may be undefined
  • Readonly properties use readonly and cannot be modified
  • Objects can be nested to create complex data structures
  • Methods can be defined as properties with function types
  • Index signatures allow dynamic property names with specific value types
  • Type aliases work for objects, primitives, unions, and more
  • Extract nested types for better reusability and maintainability
  • Use PascalCase for type alias names (convention)

What's Next?

Now that you understand objects and type aliases, you're ready to explore Enums! In the next lesson, you'll learn how to create named constants with numeric and string enums, understand when to use them, and see how they improve code readability. Enums are perfect for representing a fixed set of related values.

Get ready to organize your constants with TypeScript enums!

Mastering TypeScript objects and type aliases! Check this out!

Previous
Arrays and Tuples
Next
Enums

Never Miss a New TypeScript Tutorial

Join 1,000+ developers learning TypeScript step-by-step. Get new tutorials, type safety tips, and exclusive resources delivered to your inbox - completely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

TypeScript Tutorials

0 of 30 completed

Your Progress0%

Topics

Getting Started

  • What is TypeScript?
  • TypeScript vs JavaScript
  • Setting Up TypeScript
  • Your First TypeScript Program

Basic Types

  • Primitive Types
  • Arrays and Tuples
  • Objects and Type Aliases
  • Enums
  • Any, Unknown, and Never

Functions & Interfaces

  • Function Types and Signatures
  • Interfaces
  • Optional and Default Parameters
  • Function Overloading

Advanced Types

  • Union and Intersection Types
  • Type Guards and Narrowing
  • Literal Types
  • Type Assertions and Casting

Generics

  • Introduction to Generics
  • Generic Constraints
  • Utility Types

Classes & OOP

  • Classes and Constructors
  • Access Modifiers
  • Inheritance and Polymorphism
  • Abstract Classes and Interfaces

Practical TypeScript

  • Working with Modules
  • TypeScript with React
  • Async/Await and Promises
  • Working with APIs and JSON
  • Type Declarations and DefinitelyTyped
  • TypeScript Best Practices
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo