Welcome to your first lesson in the "TypeScript Essentials for Angular" module. Your goal is to move from using Angular as a "black box" to mastering it for your work, and that journey begins with a solid foundation in TypeScript.
In this lesson, we will tackle the first learning outcome: defining and using interfaces and type aliases to describe object shapes. In any complex application, especially the dashboards and heavy-duty forms you're building, data is constantly flowing. TypeScript allows us to give this data a precise structure, or "shape," which prevents bugs and makes our code much easier to understand and maintain.
Coming from a background with statically-typed languages like Kotlin for Android and Dart for Flutter, the idea of defining data structures with classes is familiar. TypeScript offers similar, yet distinct, tools for this purpose in the JavaScript ecosystem: interface and type. We'll explore what they are, how they're similar, what makes them different, and when you should choose one over the other.
What are Object Types?
In TypeScript, we use object types to describe the structure of an object—what properties it has and what types those properties should be. This is the essence of "structural typing," a core concept in TypeScript. Unlike nominal typing (found in languages like Java or C#) where a type is defined by its explicit declaration name, structural typing checks for compatibility based on the object's shape. If two objects have the same structure of properties and types, they are considered compatible, regardless of what they are named.
The two primary ways to give a name to an object type are with an interface or a type alias.
To begin, let's look at the basic syntax. The official TypeScript documentation provides a clear, concise introduction. Please read the first few sections to see how an object's shape can be defined.
Focus on the introduction and the three code examples that show an object type being used anonymously, with an interface, and with a type alias. You'll see that, for this simple case, they look very similar.
As you saw, both interface and type can describe the same simple object. This overlap is a common source of confusion, but by the end of this lesson, you'll have a clear framework for understanding their distinct roles.
Property Modifiers: Optional and Read-only
Before we dive into the differences, let's cover two useful modifiers you can apply to properties within any object type. These help you define shapes with more precision.
The TypeScript documentation also provides excellent explanations for optional and read-only properties.
First, read the section on Optional Properties. Note how the ? syntax allows a property to be omitted. Next, read the section on readonly Properties. It's important to understand that readonly is a compile-time check to prevent re-assignment; it doesn't make the value itself immutable if it's an object.
Here's an example combining these concepts, which is typical for defining data models in Angular:
interface User {
readonly id: number; // Cannot be changed after creation
name: string;
email?: string; // Optional property
}
const user: User = {
id: 1,
name: 'Jane Doe',
};
user.name = 'Jane Smith'; // OK
// user.id = 2; // Error: Cannot assign to 'id' because it is a read-only property.
Similarities and Differences: The Core of the Matter
While interface and type can seem interchangeable at first, they have crucial differences that influence when you should use them. We'll explore these differences, starting with a video that gives a fantastic overview.
Interfaces vs Type Aliases: what's the difference?
This video from the channel of Andrew Burgess provides a comprehensive comparison of interfaces and type aliases.
Watch the following segments to get a clear picture of their capabilities: Basic Shapes: Notice how both can define object shapes and even function signatures. Type Alias Exclusives: Pay close attention here. Type aliases can represent unions (|), intersections (&), tuples, and primitives, which interfaces cannot. This is a major advantage for type. Extension and Intersection: See how interfaces use extends and type aliases use & to combine shapes. Notice that you can mix and match them. A Key Limitation: This is critical. An interface cannot extend a type alias that is a union type. This is a strong reason to use type aliases when you need that flexibility. Declaration Merging: This is a feature unique to interfaces. We will explore this next.
Let's solidify the two most important distinctions you just saw.
1. Declaration Merging: "Open" vs. "Closed"
As the video highlighted, interfaces are "open," meaning you can define the same interface multiple times, and TypeScript will merge them into a single definition. Type aliases are "closed"; you cannot declare the same type alias twice in the same scope.
This is arguably the most significant difference.

This feature of interfaces is called declaration merging. It's powerful for augmenting existing interfaces from external libraries or built-in types (like the browser's Window object). However, it can also lead to unexpected behavior if you accidentally redefine an interface.
💥 Typescript Type Aliases vs Interfaces - When to Use Which And Why?
The Angular University channel has a video that focuses specifically on this difference.
Watch the segment from the main difference to see a practical demonstration of how interfaces can be extended after their initial declaration, while type aliases cannot.
2. Flexibility: Any Type vs. Object Shapes
The other major distinction is flexibility. A type alias, true to its name, can create a new name for any type. An interface can only describe the shape of an object or a function.
// Type aliases can do all of this:
type UserID = string; // Alias for a primitive
type Status = "pending" | "complete" | "failed"; // Union type
type Point = [number, number]; // Tuple type
type UserWithStatus = User & { status: Status }; // Intersection
// Interfaces are primarily for object shapes:
interface Admin extends User {
permissions: string[];
}
The ability of type aliases to create unions is especially important and frequently used in modern TypeScript and Angular development to model states or variations of data.
Which One Should You Use?
So, with these differences in mind, how do you choose? There are two popular schools of thought, and it's valuable to understand both.
Type vs Interface: Which Should You Use?
Renowned TypeScript expert Matt Pocock offers a modern perspective on this debate. His article argues for a "type-first" approach.
Please read the following sections: Start with the Quick Explanation for a summary. Read Use Interfaces For Object Inheritance to understand the slight performance benefit of using extends. This aligns with your goal of understanding how things work "under the hood." Read Interfaces Can Declaration Merge to see why this feature can be problematic. Finally, read the conclusion, Default to type, to understand his final recommendation.
To summarize the two main viewpoints:
-
Interface First (Classic Recommendation): Use
interfaceto define all object shapes. Only usetypewhen you need features interfaces don't have, like unions. This is the official TypeScript recommendation and is common in older codebases and many of Angular's own APIs. -
Type First (Modern Recommendation): Use
typefor everything by default. Its explicitness (no declaration merging) prevents bugs, and its flexibility is more powerful. Only useinterfacewhen you specifically need declaration merging or want to useextendsfor object inheritance hierarchies.
My Recommendation for You:
For your work in Angular, you will encounter both. Being comfortable with both is essential. For your own application code, a pragmatic approach is best:
- Use
interfacewithextendswhen defining core data models that have a clear inheritance structure (e.g.,BaseRecord,UserRecord extends BaseRecord). This is idiomatic, clean, and leverages the performance characteristics you read about. - Use
typefor everything else, especially for defining props for UI components, states that can be a union of different shapes, or simple aliases for primitives.
Consistency within your team and project is the most important factor.
Conclusion
In this lesson, we've unpacked the two ways TypeScript allows us to describe the shape of data. You now have a mental model to distinguish between them and make an informed choice.
Here are the key takeaways:
- Core Function: Both
interfaceandtypecan define the shape of an object. - Key Differences:
- Extensibility:
interfacesupports declaration merging (it's "open"), whiletypedoes not (it's "closed"). - Flexibility:
typecan alias any type (primitives, unions, tuples), whileinterfaceis for object/function shapes. - Syntax:
interfaceusesextendsfor inheritance;typeuses&(intersection) to combine shapes.
- Extensibility:
- Practical Choice: The choice depends on convention and need. Using
interfacefor object hierarchies andtypefor more flexible definitions like component props or union states is a robust and modern strategy.
Now that you can define the shape of your data, the next logical step is to write code that can work with any shape. In our next lesson, we will explore generics, a powerful feature that allows us to write reusable, type-safe functions and classes that operate on a variety of types without sacrificing type safety.