Interfaces for Data Shapes
Interfaces define the shape of objects. In Angular, they are used to type component inputs, service responses, and configuration objects.
Defining and Using Interfaces
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'editor' | 'viewer';
}
interface CreateUserRequest {
name: string;
email: string;
role?: 'admin' | 'editor' | 'viewer';
}
Using Interfaces in Angular Components
import { Component, Input } from '@angular/core';
interface CardData {
title: string;
description: string;
imageUrl?: string;
}
@Component({
selector: 'app-card',
template: `
<div class="card">
<h3>{{ data.title }}</h3>
<p>{{ data.description }}</p>
<img *ngIf="data.imageUrl" [src]="data.imageUrl" [alt]="data.title">
</div>
`,
})
export class CardComponent {
@Input({ required: true }) data!: CardData;
}
Optional and Readonly Properties
interface Config {
apiUrl: string; // required
timeout?: number; // optional
readonly retries: number; // cannot be reassigned
}
Interface vs Type Alias
| Feature | Interface | Type Alias |
|---|---|---|
| Object shapes | Yes | Yes |
| Union types | No | Yes |
| Intersection types | No | Yes |
| Declaration merging | Yes | No |
| Extends | Yes | Yes (via &) |
// Interface — preferred for object shapes
interface ButtonProps {
label: string;
disabled?: boolean;
}
// Type alias — needed for unions
type Status = 'idle' | 'loading' | 'success' | 'error';
type Result<T> = { success: true; data: T } | { success: false; error: string };
Union Types and Discriminated Unions
Union types allow a variable to hold one of several types. They are essential for modeling state that can take different shapes.
Basic Union Types
type ID = string | number;
function formatId(id: ID): string {
return id.toString();
}
Discriminated Unions
A discriminated union uses a common literal property to distinguish between variants:
type ApiState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: string };
function renderState<T>(state: ApiState<T>): string {
switch (state.status) {
case 'idle':
return 'Waiting...';
case 'loading':
return 'Loading...';
case 'success':
return `Data: ${JSON.stringify(state.data)}`;
case 'error':
return `Error: ${state.error}`;
}
}
Union Types in Angular Templates
@Component({
selector: 'app-status',
template: `
<div [ngSwitch]="status.type">
<p *ngSwitchCase="'success'">{{ status.message }}</p>
<p *ngSwitchCase="'error'">{{ status.message }}</p>
<p *ngSwitchDefault>Unknown status</p>
</div>
`,
})
export class StatusComponent {
@Input() status!: { type: 'success'; message: string } | { type: 'error'; message: string };
}
Type Narrowing
TypeScript narrows union types based on checks:
function process(value: string | number | null) {
if (value === null) {
return 'No value';
}
// TypeScript knows value is string | number here
if (typeof value === 'string') {
return value.toUpperCase(); // narrowed to string
}
return value.toFixed(2); // narrowed to number
}
Quiz
1. What is the main difference between an interface and a type alias?
2. What is a discriminated union?
3. How do you make a property optional in a TypeScript interface?
Flashcards
Question
When should you use an interface vs a type alias?
Click to reveal answer
Answer
Use interfaces for object shapes (especially public APIs). Use type aliases for unions, intersections, and mapped types.
Question
What is a discriminated union?
Click to reveal answer
Answer
A union where each member shares a common literal property (like 'status') that TypeScript uses for type narrowing.
Question
How do you type a component input that can be string or number?
Click to reveal answer
Answer
Use a union type: @Input() value!: string | number;
Revision Notes
Key Takeaways
- 1. Interfaces define object shapes for inputs and payloads
- 2. Union types model fields that accept multiple shapes
- 3. Discriminated unions enable safe type narrowing
- 4. TypeScript catches type errors at compile time
Interview Tips
- • Explain when to prefer interface over type alias
- • Be ready to demonstrate discriminated unions for API state
- • Mention how TypeScript's type system prevents runtime errors
Cheat Sheet
TypeScript Types Cheat Sheet
Interface (object shapes):
interface User {
id: number;
name: string;
email?: string;
readonly role: string;
}
Union types:
type Status = 'idle' | 'loading' | 'success' | 'error';
Discriminated union:
type ApiState<T> =
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: string };
Type narrowing:
if (typeof value === 'string') { /* string */ }
if (value === null) { /* null */ }