Defining Object Shapes with Interfaces in TypeScript
Learn how to define object shapes with TypeScript interfaces. Master data structures and typing to ensure your task API client remains bug-free.

Previously in this course, we covered Type Inference in Practice and established how TypeScript automatically detects types. While inference is powerful, it falls short when you need to define the predictable structure of complex data. In this lesson, we move beyond simple primitives to define the "shape" of our data using interfaces.
What is an Interface?
In TypeScript, an Interface is a blueprint for an object. Think of it as a contract: when you define an interface, you are telling the compiler exactly which properties an object must have, what their names are, and what types they expect.
If you have worked with backend languages or Data Transfer Objects (DTOs), this concept will feel familiar. By defining the shape of your Task object now, you ensure that every part of your application treats task data consistently.
Defining a Task Interface
To start building our task API client, we need a standard structure for a Task. Instead of passing around loose JavaScript objects, we define an interface:
TYPESCRIPTinterface Task { id: number; title: string; isCompleted: boolean; priority: number; }
This interface declares that any Task object must have these four properties. If you try to create an object missing one of these, or with the wrong type (e.g., passing a string into priority), TypeScript will trigger a compile-time error.
Annotating Objects with Interfaces
Once the interface is defined, you can use it to annotate your variables. This is where we move from "I hope this object has the right data" to "The compiler guarantees this object has the right data."
TYPESCRIPTconst myTask: Task = { id: 1, title: "Complete TypeScript lesson", isCompleted: false, priority: 1 }; // This would cause an error because the structure doesn't match the interface: const brokenTask: Task = { id: 2, title: "Incomplete Task" // Error: Property CE9178">'isCompleted' is missing };
Why Interfaces Matter for Data Structures
Using interfaces for Data Structures provides three immediate benefits:
- Self-Documentation: Developers can look at the interface and instantly know what data a task requires.
- Autocomplete: Your IDE will suggest property names as you type, reducing the risk of typos.
- Refactoring Safety: If you rename
titletolabelin the interface, TypeScript will highlight every single place in your code that needs updating.
Hands-on Exercise
To advance our project, create a new file named task.ts. Define a Task interface that includes a createdAt property (use the string type). Then, create an array of two task objects that adhere to this interface.
Try to intentionally break the structure to see how the TypeScript compiler reacts in your terminal.
Common Pitfalls
- Excess Properties: TypeScript is strict. If your object has properties not defined in the interface, the compiler will complain. This prevents you from accidentally polluting your data with unused fields.
- Case Sensitivity: Interfaces are case-sensitive.
idis not the same asId. Stick to camelCase for consistent API naming conventions. - Ignoring the Interface: Don't be tempted to use
anyjust to silence an error. If an object doesn't fit the interface, fix the object, don't bypass the type checker.
FAQ
Can I add methods to an interface? Yes. While we are currently focusing on data structures, interfaces can also define function signatures for object methods.
What happens if I forget a property?
TypeScript will throw a Property '...' is missing in type error, preventing the code from compiling until the object matches the shape.
Are interfaces removed at runtime? Yes. Interfaces are a compile-time construct. They are stripped out during the transpilation process, meaning they have zero impact on your application's bundle size or performance.
Recap
We’ve moved from simple primitives to defining robust object shapes. By using interfaces, you’ve established a clear contract for your Task objects, ensuring that your API client handles data with predictable structure. This validation is a cornerstone of professional, maintainable TypeScript development.
Up next: Using Type Aliases — where we explore another way to define shapes and learn when to choose an interface over a type alias.
Work with me

React & Next.js Dashboard / Admin UI Development
A clean, data-rich dashboard UI in React or Next.js — charts, tables, and real-time data that your users will actually enjoy using.

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.


