TypeScript Objects
Objects & Interfaces
Describing the shape of objects is TypeScript's bread and butter. Interfaces and type aliases both do it, and structural typing decides what counts as a match.
TypeScript 5
✓ Core Concepts
3 Topics
01
interface vs type alias
Both describe an object's shape and are mostly interchangeable. interface can be re-opened and extended; type can express unions and other shapes an interface cannot.
TypeScript — interface & type
interface User { name: string; age: number; } // type alias — same shape type Point = { x: number; y: number }; // interface: extend and merge interface Admin extends User { role: string; } // type: unions and things interface can't do type ID = string | number; type Pair = [number, number]; // tuple
| interface | type | |
|---|---|---|
| Object shapes | Yes | Yes |
| Unions / tuples | No | Yes |
| Extend | extends | Intersection & |
| Declaration merging | Yes (re-open) | No |
Rule of thumb: use
interface for object shapes and public APIs (it merges and reads cleanly), and type when you need unions, tuples, or mapped/conditional types. Teams often standardise on one for consistency.02
Optional, readonly & Index Signatures
TypeScript — Property Modifiers
interface Config { readonly id: string; // can't be reassigned after creation name: string; timeout?: number; // optional — number | undefined [key: string]: unknown; // index signature — arbitrary extra keys } const c: Config = { id: "a1", name: "prod" }; // c.id = "a2"; // Error: readonly property c.timeout; // number | undefined — must handle undefined c.anything = 42; // allowed via index signature // readonly arrays and tuples const nums: readonly number[] = [1, 2, 3]; // nums.push(4); // Error: push doesn't exist on readonly array
readonly is a compile-time guarantee only. It stops you from reassigning, but the underlying JavaScript object is still mutable at runtime. It's not Object.freeze.03
Structural Typing
TypeScript uses structural typing ("duck typing"): a value is compatible with a type if it has the required shape, regardless of whether it was declared with that type's name. Java and C++ use nominal typing, where names must match.
TypeScript — Shape, Not Name
interface Named { name: string; } function greet(x: Named) { return `Hi ${x.name}`; } // this object was never declared as Named, but it fits the shape const dog = { name: "Rex", breed: "Lab" }; greet(dog); // OK — has a string 'name', extra props ignored // object literals get "excess property checks" when passed directly // greet({ name: "x", breed: "y" }); // Error: 'breed' not in Named
Structural typing makes TypeScript flexible: anything with the right shape works, no explicit
implements needed. The exception is excess property checks on object literals passed directly to a function, which catch typos in optional props.✓
Quick Quiz
1. Which can express a union type?
2. Which supports declaration merging (re-opening)?
3. readonly on a property is enforced…
4. TypeScript's type compatibility is based on…
5. An index signature [key: string]: unknown allows…