🀝 Interfaces & Type Aliases

TypeScript Fundamentals β€” Interfaces & Type Aliases
TypeScript Fundamentals
Course 1 Β· Chapter 4 Β· Interfaces & Type Aliases

🀝 Interfaces & Type Aliases

So far, you've written type annotations inline. As your code grows, repeating the same object shape becomes tedious and error-prone. This chapter introduces two ways to name and reuse types: type aliases and interfaces. Both solve the problemβ€”knowing when to use each is the art.

🏷️ Type Aliases

A type alias gives a name to any type using the type keyword. It's like assigning a type to a variable.

Basic Type Alias

type Age = number; const myAge: Age = 30; // βœ… Works const yourAge: Age = "thirty"; // ❌ Error! Type 'string' is not assignable to type 'number'

Type Alias for Objects

The real power: reuse object shapes across your codebase:

type User = { name: string; email: string; age: number; isActive?: boolean; }; const user1: User = { name: "Alice", email: "alice@example.com", age: 30 }; const user2: User = { name: "Bob", email: "bob@example.com", age: 25, isActive: true }; // βœ… Both match the User type greet(user1); greet(user2);

Union Type Aliases

Type aliases shine with unions β€” combining multiple types:

type ID = string | number; type Status = "pending" | "active" | "inactive"; const userId: ID = 42; // βœ… number is OK const username: ID = "user123"; // βœ… string is OK const currentStatus: Status = "active"; // βœ… Valid status const badStatus: Status = "deleted"; // ❌ Not a valid status option

πŸ“‹ Interfaces

An interface is specifically for describing the shape of objects. It's similar to a type alias for objects, but with some key differences (which we'll explore).

Basic Interface

interface User { name: string; email: string; age: number; isActive?: boolean; } const user: User = { name: "Alice", email: "alice@example.com", age: 30 };

Notice the syntax difference: no `=` sign, no curly braces required.

Extending Interfaces

Interfaces can inherit from other interfaces using extends:

interface User { name: string; email: string; } interface AdminUser extends User { role: "admin"; permissions: string[]; } // AdminUser now has name, email, role, and permissions const admin: AdminUser = { name: "Alice", email: "alice@example.com", role: "admin", permissions: ["read", "write", "delete"] };

Merging Interfaces

A unique power of interfaces: you can declare the same interface multiple times and they merge:

interface User { name: string; } interface User { age: number; } // User now has both name AND age const user: User = { name: "Alice", age: 30 };

This is powerful for adding properties to types across different files (think plugins).

βš–οΈ Type Aliases vs Interfaces

When to Use Each

Use Interfaces For:
  • Object shapes (contracts)
  • Classes to implement
  • Code that merges types
  • Public API definitions
Use Type Aliases For:
  • Unions (string | number)
  • Tuples ([string, number])
  • Primitives (numbers, strings)
  • Complex compositions

Key Differences

βœ… Interfaces can extend
interface Admin extends User { ... }
βœ… Interfaces merge
interface Window { x: number; } interface Window { y: number; }
βœ… Types support unions
type Status = "on" | "off";
βœ… Types are more flexible
type Callback = () => void;

πŸ”§ Methods in Interfaces

Interfaces can describe methods (functions) as properties:

interface Logger { log(message: string): void; error(message: string): void; } const consoleLogger: Logger = { log: (msg) => console.log(msg), error: (msg) => console.error(msg) };

πŸ”’ Readonly and Intersection Types

Readonly Properties

interface Config { readonly apiKey: string; port: number; } const config: Config = { apiKey: "secret", port: 3000 }; config.port = 4000; // βœ… Fine config.apiKey = "newsecret"; // ❌ Error! Cannot assign to readonly

Intersection Types (Preview)

Combine multiple types into one using &:

type Employee = User & { employeeId: number }; // Employee has all properties from User PLUS employeeId const emp: Employee = { name: "Alice", email: "alice@example.com", age: 30, employeeId: 12345 };

πŸ’» Coding Challenges

Challenge 1: Create a User Type Alias

Define a type alias for a user with:

  • id (number)
  • username (string)
  • email (string)
  • isVerified (boolean, optional)

Goal: Create the type alias and use it to define 2-3 user objects.

β†’ Solution

Challenge 2: Extend an Interface

Create a base Person interface with name and age, then create an Employee interface that extends it and adds:

  • employeeId (number)
  • department (string)

Goal: Demonstrate interface inheritance.

β†’ Solution

Challenge 3: Union Type for Status

Create a Status type that can only be one of: "pending", "approved", or "rejected". Then create a function that accepts this type and logs the status.

function handleStatus(status: Status): void { // Your implementation }

Goal: Demonstrate union types with literals.

β†’ Solution

πŸ’‘ Real-World Tip: Start with Interfaces

As a beginner, favor interfaces for object shapes and type aliases for everything else. Interfaces are slightly more limited, which forces you to write clearer, more maintainable code. You can always switch to a type alias if you need unions or other advanced features.

🎯 What's Next

Now that you can define contracts with types and interfaces, Chapter 5 introduces Classes & Object-Oriented TypeScript, where you'll see interfaces in action as contracts that classes implement.