Interfaces & Type Aliases
π€ Interfaces & Type Aliases
π·οΈ Type Aliases
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
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
interface Admin extends User { ... }
interface Window { x: number; } interface Window { y: number; }
type Status = "on" | "off";
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.
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.
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.
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.