TypeScript Interface
To define bespoke data structures and improve type safety in TypeScript, the ideas of Interfaces and Type Aliases (type) are essential. When defining basic object shapes, they frequently seem functionally identical, but they have different purposes and capabilities, especially when it comes to extension and type composition.
Interfaces ()
The fundamental method in TypeScript for combining several type annotations into a single named annotation is through an interface. Declaring the structure, or shape, of variables and objects is its main objective. An object’s expected attributes and functions are listed by interfaces.
Defining Object Shapes/Structure
You are establishing a named contract that objects must follow when you define an interface. Consistency between various codebase sections is guaranteed by this structural specification.
Define a Name
interface, for instance, to ensure that any object defined with this type has certain attributes with specified types:
// Interface definition
interface Name {
first: string;
second: string;
}
var personName: Name;
personName = {
first: 'John',
second: 'Doe'
}; // Correct structure
// Example showing type enforcement at compile time:
personName = {
first: 'John'
}; // Error: `second` is missing [7]
personName = {
first: 'John',
second: 1337 // Error: `second` is the wrong type [7]
};
A new annotation (Name
) that applies type checks to each member is produced by the combination of the annotations (first: string
+ second: string
). Because TypeScript employs structural typing, any object that fits the structure of the interface can be used as an instance of it.
Zero Runtime JavaScript Impact
The fact that interfaces only exist in the TypeScript type system is a crucial characteristic. The type checker uses them as a development-time construct to define expected forms.
Interfaces don’t affect runtime JS at all. The interface definitions are totally removed when the code is transpiled to JavaScript using the TypeScript compiler (TSC).
As a result, runtime JavaScript code cannot make reference to an interface.
interface Poet {
name: string;
}
console.log(Poet);
// Output/Error: Error: 'Poet' only refers to a type,
// but is being used as a value here.
Expanding Interfaces
The extends
keyword is used in interfaces to facilitate hierarchical relationships. All of the members of one or more existing interfaces may be inherited by an interface. Extending classes is analogous to this method.
interface IPerson {
name: string;
age: number;
breath(): void;
}
// IManager inherits name, age, and breath()
interface IManager extends IPerson {
managerId: number;
managePeople(people: IPerson[]): void;
}
```
This capacity for extension also applies to defining class implementations, where a class can declare that its instances adhere to an interface using the `implements` keyword .
### Interface Merging/Open-Endedness
TypeScript interfaces are **open ended** . This unique characteristic, known as **declaration merging**, means that if you declare multiple interfaces with the same name in the same scope, TypeScript automatically combines all members into a single type definition.
This extensibility is a **vital tenet of TypeScript** that allows mimicking the highly dynamic and extensible nature of JavaScript. It is particularly useful when declaring types for external JavaScript libraries (ambient declarations) or adding custom properties to native types (like modifying the global `Window` interface).
Consider interfaces defined in separate declaration files:
```typescript
// lib-a.d.ts
interface Point {
x: number;
y: number;
}
// lib-b.d.ts
// This declaration is merged with the previous one
interface Point {
z: number;
}
// Your code sees the combined result:
var myPoint: Point; // { x: number; y: number; z: number; }
myPoint.z = 100; // Allowed!
Type Aliases ()
Any type annotation can have a new name (alias) created for it using the type
keyword. Because of this feature, type aliases are incredibly versatile for expressing intricate type compositions that interfaces are unable to manage directly.
Type Aliases for Simpler Structures, Unions, or Intersections
The recommended method for giving semantic names to types other than object shapes like primitive types, function signatures, unions, intersections, or tuples is to use type aliases.
- Union Types: Union types (e.g.,
string | number
) let a value be one of several types. When naming these intricate constructions, type aliases are crucial: - Intersection Types: These kinds use the
&
operator to combine the elements of two or more types. All intersecting kinds’ features are included in the final type. - Simpler Structures (Tuples): Type aliases are perfect for providing array structures such as tuples with semantic names.
Interface vs. Type Aliases
Although object shapes can be determined by both interface
and object literal types declared using type
aliases, there are particular rules on when to give one priority over the other.
Feature | interface (Interface) | type (Type Alias) |
Object Definition | Defines object shapes/structure. | Can define object shapes using object literal syntax. |
Extensibility (Hierarchy) | Uses extends to create new hierarchies, allowing extension of multiple interfaces. | Uses intersection types (&) to combine existing types, which is similar but functionally different from extension. |
Class Compatibility | Uses implements to enforce class shape adherence. | Cannot be used directly with implements unless aliasing an interface. |
Composition | Best for combining object types using extends . | Best for combining types using **Union (` |
Open-Endedness | Supports declaration merging (open-ended). | Cannot be merged; duplicate names are compilation errors. |
Type Scope | Primarily limited to object shapes. | Can alias any type, including primitives, unions, intersections, and mapped types. |
Recommendations
The main recommendation derived from the setting priorities according to intended use:
- When you want to
implement
orextend
, use the interface. Use aninterface
if you require type annotation hierarchies. - When a union or intersection may be required, use a type alias. A
Type
alias is the best option if you wish to give Union or Intersection types semantic names. - To give simpler object structures (like Coordinates) a semantic name, use a
type
alias. - Use whatever makes you happy that day if the choice is unclear (for example, establishing a basic object form without plans to create a class or merge).