What is interface in TypeScript?
In TypeScript, an interface is a powerful feature that defines the 'shape' of an object. It acts as a blueprint, providing a way to specify the names and types of properties and methods that an object must have. Interfaces are primarily used for type-checking during development and compilation, helping to enforce contracts within your code.
What is an Interface?
An interface is a virtual structure that is only used for type-checking. It allows you to describe the exact structure that an object should adhere to, ensuring that any object assigned to a variable of that interface type will have all the specified properties and methods with their corresponding types. This promotes consistency and helps catch errors early in the development cycle.
Key Characteristics
- Structural Typing: TypeScript's type system is based on structural subtyping (also known as 'duck typing'). If two types have the same members, they are considered compatible, regardless of whether they explicitly declare themselves to implement the same interface. Interfaces define these structures.
- Compile-Time Only: Interfaces are completely removed during transpilation to JavaScript. They do not exist at runtime and therefore add no overhead to the compiled JavaScript code.
- Enforce Contracts: They provide a contract for objects, functions, and classes, ensuring that they conform to a specific structure.
- Readability and Maintainability: By explicitly defining the expected shape of data, interfaces improve code readability and make it easier to maintain large codebases.
Basic Syntax and Example
You define an interface using the interface keyword, followed by its name and a block containing its members (properties and methods).
interface Person {
firstName: string;
lastName: string;
age?: number; // Optional property
greet(): string;
}
function sayHello(person: Person): void {
console.log(`Hello, ${person.firstName} ${person.lastName}!`);
if (person.age) {
console.log(`You are ${person.age} years old.`);
}
console.log(person.greet());
}
const user: Person = {
firstName: "Alice",
lastName: "Smith",
age: 30,
greet: function() {
return "Nice to meet you!";
}
};
sayHello(user);
const anotherUser: Person = {
firstName: "Bob",
lastName: "Johnson",
greet: () => "Greetings!"
};
sayHello(anotherUser);
Common Use Cases
- Describing Object Shapes: The most common use is to define the shape of objects, ensuring they have specific properties and methods.
- Function Types: Interfaces can describe the shape of function types, specifying parameter types and return types.
- Class Implementation: Classes can implement interfaces, which then requires the class to conform to the interface's structure.
- Dictionary/Indexable Types: Interfaces can describe objects that can be indexed with string or number keys.
- Extending Interfaces: Interfaces can extend other interfaces, inheriting their members and adding new ones.
Extending Interfaces
Interfaces can extend one or more existing interfaces, creating a new interface that combines all members from the extended interfaces.
interface Named {
name: string;
}
interface Aged {
age: number;
}
interface PersonWithDetails extends Named, Aged {
email: string;
}
const detailedPerson: PersonWithDetails = {
name: "Charlie",
age: 45,
email: "charlie@example.com"
};
console.log(detailedPerson);
Interfaces vs. Type Aliases
While interfaces and type aliases (type) can often be used for similar purposes (describing object shapes), there are some key differences:
- Declaration Merging: Interfaces support declaration merging (you can define an interface with the same name multiple times, and TypeScript will merge their members). Type aliases do not.
- Extensibility: Both can extend/intersect, but interfaces use extends while type aliases use intersection types (&).
- Performance/Compiler: In many cases, the performance impact is negligible, but interfaces are generally preferred when defining the shape of an object or class contract, especially when declaration merging is beneficial.