TypeScript Interfaces: Naming the Shape of Your Data
An interface is a contract for an object's shape, caring what properties it has, not its class. Use it to define function parameters or API responses. The footgun: TypeScript allows objects with extra properties, checking only for the required ones.
WHY IT EXISTS JavaScript is dynamically typed, meaning you don't know the shape of an object until runtime, which can lead to errors like cannot read property 'x' of undefined. TypeScript's interfaces solve this by letting you describe the required shape of an object, providing compile-time safety and self-documenting code.
THE MENTAL MODEL An interface is a blueprint for an object's structure, not a class you instantiate. It's a named contract that says, "Any object that wants to be treated as a User must have at least a name string and an id number." This is called "structural typing" or "duck typing": if it walks and quacks like a duck, TypeScript considers it a duck.
HOW IT WORKS You declare an interface with the interface keyword, a name, and a body defining properties and their types. TypeScript's type checker then verifies that any object assigned to a variable or passed to a function expecting that interface has, at a minimum, all the required properties. It doesn't care about extra properties on the object, only that the contract is fulfilled. You can also mark properties as optional with a ? suffix, which is useful for patterns like configuration objects.
WHEN TO USE IT Use interfaces to define the shape of objects for function arguments and return values. They are perfect for describing the structure of data coming from an external API (e.g., interface ApiResponse { ... }) or for creating reusable type definitions to enforce consistency across your project.
WHEN NOT TO USE IT If you need to store actual implementation logic (methods with bodies) or create instances with new, use a class. If you need to define a union, intersection, or a type from a primitive, use a type alias. Interfaces are for describing the shape of objects, not for complex type manipulations or implementation details.
ONE CANONICAL EXAMPLE A function needs an object with a label. Instead of an anonymous type { label: string }, we define an interface: interface LabeledValue { label: string; }. The function printLabel(obj: LabeledValue) now has a clear contract. We can pass it an object like { size: 10, label: "Size 10 Object" }. Even though it has an extra size property, TypeScript allows it because it fulfills the LabeledValue contract by having a label that is a string.
Read the original → typescriptlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.