🌱BeginnerObject Types & Interfaces
Interfaces
Define object shapes with interface optional properties, readonly, extending, and declaration merging.
Overview
An `interface` in TypeScript describes the shape (structure) of an object. It specifies which properties an object must have and what types those properties are. Any object that has the required properties satisfies the interface TypeScript uses structural typing, not nominal typing.
Interfaces support:
- **Optional properties** (`?`) may or may not be present
- **Readonly properties** (`readonly`) cannot be changed after creation
- **Method signatures** define what methods an object must have
- **Extending** one interface can extend another (or multiple)
- **Declaration merging** multiple declarations of the same interface name are merged
Interfaces are erased at compile time no runtime overhead.
Key Points
- •`interface Name { prop: Type; }` defines an object shape
- •Optional property: `prop?: Type` may be absent; type is `Type | undefined`
- •Readonly: `readonly prop: Type` assignable once, then immutable
- •Method signature: `method(arg: Type): ReturnType` or arrow form `method: (arg: Type) => ReturnType`
- •Extending: `interface B extends A { ... }` B has all of A's properties plus its own
- •Multiple inheritance: `interface C extends A, B { ... }`
- •Declaration merging: redeclaring the same interface name adds properties (useful for extending global types)
Examples
Basic interface with optional and readonly
interface User {
readonly id: number; // cannot change after creation
name: string;
email: string;
age?: number; // optional User | undefined
role?: "admin" | "user" | "guest";
}
const alice: User = {
id: 1,
name: "Alice",
email: "alice@example.com",
role: "admin",
};
// alice.id = 2; // Error: Cannot assign to 'id' because it is a read-only property
// Optional property is undefined if not provided
console.log(alice.age); // undefined
function greetUser(user: User): string {
return `Hello, ${user.name}!${user.role ? ` [${user.role}]` : ""}`;
}
console.log(greetUser(alice)); // Hello, Alice! [admin]Interface with methods and extending
interface Shape {
readonly name: string;
area(): number;
perimeter(): number;
toString(): string;
}
interface ColoredShape extends Shape {
color: string;
}
interface LabeledShape extends Shape {
label: string;
}
// Must implement all methods
const circle: ColoredShape = {
name: "circle",
color: "red",
area: () => Math.PI * 5 * 5,
perimeter: () => 2 * Math.PI * 5,
toString: () => "Circle(r=5)",
};
console.log(circle.area().toFixed(2)); // 78.54
console.log(circle.toString()); // Circle(r=5)Index signatures dynamic keys
// When you don't know all property names upfront
interface StringMap {
[key: string]: string;
}
const translations: StringMap = {
hello: "hola",
world: "mundo",
goodbye: "adios",
};
console.log(translations["hello"]); // "hola"
translations["thanks"] = "gracias"; // ok
// Mixed: known + dynamic keys
interface Config {
version: string; // known key
[key: string]: string | number; // dynamic keys (must be compatible with known)
}
const cfg: Config = {
version: "1.0",
timeout: 5000,
endpoint: "https://api.example.com",
};Common Mistakes
- Confusing optional (`?`) with possibly-null `age?: number` means `number | undefined`, not `number | null`
- Trying to implement an interface on a plain object with extra properties TypeScript uses excess property checking on object literals but not on assigned variables
- Forgetting that interfaces don't generate any JavaScript they exist only at type-check time
Note
Use `readonly` on all properties that shouldn't change after construction it documents intent and TypeScript enforces it. For function parameters, accepting `Readonly<T>` communicates "I won't mutate this" to callers.
Exercises
Write TypeScript code to solve each exercise. Click Run to compile and execute it right here, then mark as done.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4