TypeScript: TypeScript interface (interface)
Last updated: 2026-08-26
An interface is the core way TypeScript defines the structure of an object—it describes "which properties and methods an object must have," but does not provide an implementation.
1. Basic Syntax of Interfaces
(1) Define an interface
interface User {
name: string;
age: number;
email: string;
}
(2) Using the Interface
let user: User = {
name: "Charlie",
age: 20,
email: "xiaoming@example.com"
};
(3) Interfaces as Function Parameters
function greet(user: User): string {
return `Hello,${user.name}!How old are you this year?${user.age} years old。`;
}
console.log(greet({ name: "Diana", age: 22, email: "hong@example.com" }));
Output:
Hello,Diana!How old are you this year?22 years old。
(4) Methods for Describing Interfaces
Interfaces can describe not only properties but also method signatures:
interface Animal {
name: string;
speak(): string;
move(distance: number): void;
}
let dog: Animal = {
name: "Wangcai",
speak() { return "Woof!"; },
move(distance) { console.log(`${this.name} Moved ${distance}m`); }
};
console.log(dog.speak()); // "Woof!"
dog.move(10); // "Wangcai Moved 10m"
2. Optional Properties and Read-Only Properties
(1) Optional Attribute ?
interface Config {
host: string;
port: number;
debug?: boolean; // Optional
timeout?: number; // Optional
}
// Optional attributes may be omitted.
let config: Config = { host: "localhost", port: 3000 };
let config2: Config = { host: "localhost", port: 3000, debug: true };
(2) Read-Only Property readonly
interface Point {
readonly x: number;
readonly y: number;
}
let point: Point = { x: 1, y: 2 };
// point.x = 10; // ❌ Read-only properties cannot be modified.
(3) ReadonlyArray and Interfaces
interface TodoList {
readonly name: string;
readonly items: readonly string[]; // items Both the array itself and its contents are read-only.
}
let todo: TodoList = {
name: "Today's Tasks",
items: ["Write code", "Test", "Deployment"]
};
// todo.items.push("New Task"); // ❌ Read-only arrays cannot be modified.
// todo.name = "Tomorrow's Tasks"; // ❌ Read-only properties cannot be modified.
3. Interface Inheritance (extends)
Interfaces can inherit from other interfaces via extends to enable type composition and reuse:
(1) Single Inheritance
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: string;
department: string;
}
let emp: Employee = {
name: "Charlie",
age: 28,
employeeId: "E001",
department: "Engineering Department"
};
(2) Multiple Inheritance
An interface can inherit from multiple interfaces at the same time:
interface Serializable {
serialize(): string;
}
interface Loggable {
log(message: string): void;
}
interface Entity extends Serializable, Loggable {
id: number;
}
let item: Entity = {
id: 1,
serialize() { return JSON.stringify({ id: this.id }); },
log(message) { console.log(`[${this.id}] ${message}`); }
};
(3) Override Properties
A child interface can override the property types of a parent interface, but it must be compatible:
interface Base {
data: string | number;
}
interface Derived extends Base {
data: string; // ✅ Narrowing — string is a subtype of string | number
}
▶ Example: Building Hierarchical Types Using Inheritance
// Basic Interfaces
interface Shape {
color: string;
}
// Extension Interface
interface Square extends Shape {
sideLength: number;
}
interface Circle extends Shape {
radius: number;
}
// Usage
let square: Square = { color: "Red", sideLength: 10 };
let circle: Circle = { color: "Blue", radius: 5 };
function describeShape(shape: Shape): string {
return `One${shape.color}the graphic`;
}
console.log(describeShape(square)); // "A red shape"
console.log(describeShape(circle)); // "A blue shape"
Output:
One Red graphic
One Blue graphic
4. Declaration Merging
A unique feature of interfaces—interfaces with the same name automatically merge their properties:
(1) Basic Merge
interface Window {
title: string;
}
interface Window {
count: number;
}
// Equivalent to:
// interface Window {
// title: string;
// count: number;
// }
let win: Window = { title: "Main Window", count: 3 };
(2) Rules for Merging
- Properties with the same name must have the same type; otherwise, an error will be reported.
- Merging method signatures into overloaded methods
- Interfaces declared later appear at the top of the overload list (and have higher priority)
interface Calculator {
compute(a: number, b: number): number;
}
interface Calculator {
compute(a: string, b: string): string;
}
// After the merger compute There are two overloads
let calc: Calculator = {
compute(a: any, b: any): any {
return a + b;
}
};
console.log(calc.compute(1, 2)); // 3
console.log(calc.compute("a", "b")); // "ab"
(3) Practical Use: Extending Third-Party Types
// For the built-in Window Adding Custom Properties to an Interface
interface Window {
myCustomProperty: string;
}
// It is now safe to use
// window.myCustomProperty = "hello"; // ✅
interface instead of type to extend the types of third-party libraries— type does not support type union, but interface does.
5. Index Signatures and Interfaces
Index signatures can also be used in interfaces:
interface StringMap {
[key: string]: string;
}
let translations: StringMap = {
hello: "Hello",
goodbye: "Goodbye",
thanks: "Thank you"
};
// Add a new key-value pair
translations["sorry"] = "I'm sorry";
When an index signature and known attributes coexist, the types of the known attributes must be compatible:
interface Config {
[key: string]: string | number;
host: string; // ✅ string is a subtype of string | number
port: number; // ✅ number is a subtype of string | number
// debug: boolean; // ❌ boolean No string | number subtypes of
}
6. The Difference Between Interfaces and Type Aliases
Both interfaces and types can define object types, but there are the following differences:
| Feature | interface | type |
|---|---|---|
| Object Type | ✅ Primary Use | ✅ Can Also Be Used For |
| Statement Merging | ✅ Supported | ❌ Not Supported |
| Inheritance | extends |
& Cross-type |
| Union Type | ❌ Cannot be defined directly | ✅ type A = B | C |
| Aliases for Basic Types | ❌ Not allowed | ✅ type ID = string |
| Computed Properties | ❌ Not supported | ✅ Supported |
| instanceof | ✅ class implements | ❌ Cannot |
(1) When to use an interface
- Define object shapes (API responses, configuration objects, data models)
- Requires
extendsfor inheritance - Requires a declaration of a merge (to extend a third-party type)
- class implements (a class implements an interface)
(2) When to use type
- Composite Type:
type Status = "active" | "inactive" - Aliases for Basic Types:
type ID = string | number - Advanced operations such as conditional types and mapping types
- Underlying Definitions of Tool Types
interface for object types and type for union types and operations on advanced types. The two are not mutually exclusive and can be used together in the same project.
▶ Example: Optional and Readonly Properties in Practice
interface UserProfile {
readonly id: number;
name: string;
email: string;
nickname?: string;
readonly createdAt: Date;
}
let user: UserProfile = {
id: 1,
name: "Charlie",
email: "charlie@example.com",
createdAt: new Date()
};
user.name = "Diana"; // ✅ name is mutable
// user.id = 2; // ❌ readonly property
console.log(user.nickname); // undefined (optional)
Output:
undefined
▶ Example: Extending Interfaces for Type Composition
interface Timestamped {
createdAt: Date;
updatedAt: Date;
}
interface Owned {
ownerId: number;
ownerName: string;
}
interface Article extends Timestamped, Owned {
title: string;
content: string;
}
let article: Article = {
title: "Hello TypeScript",
content: "TypeScript is great...",
createdAt: new Date(),
updatedAt: new Date(),
ownerId: 1,
ownerName: "Charlie"
};
console.log(`${article.ownerName}: ${article.title}`);
Output:
Charlie: Hello TypeScript
❓ FAQ
interface or type?interface to define the "shape of an object," and use type to define a "type alias" or "union type." If your team already has a convention, just follow it. In 90% of cases, the two are equivalent, so don't overthink it.type?interface extends can inherit any object type alias defined by type. Conversely, type can also combine interfaces using cross-types &. The two are fully interoperable.type. interface Fn { (a: string): number } is equivalent to type Fn = (a: string) => number, and the latter is more concise and intuitive. We recommend using type for function types.📖 Summary
- An interface describes the structure of an object—its properties, their types, and the signatures of its methods
?marks an optional property;readonlymarks a read-only property; the two can be combined asreadonly x?: number- Interfaces are inherited using
extendsand support both single and multiple inheritance; child interfaces can narrow the property types of their parent interfaces. - Note that merging is a feature unique to interfaces—interfaces with the same name are automatically merged, which is used to extend third-party types.
interfaceis suitable for defining object shapes, whiletypeis suitable for union types and advanced operations; in everyday development, the two are often used interchangeably.
📝 Exercises
- Basic Problem (Difficulty ⭐): Define the
Bookinterface (title, author, pages, isbn?), create two book objects, and print them. Note that isbn is an optional property. - Advanced Problem (Difficulty ⭐⭐): Define the
Shapebase interface (with the color and area methods), then defineCircleandRectangleso that they each inherit from Shape and add their own properties. Write a function that takes a parameter of type Shape and calls the area method. - Challenge (Difficulty: ⭐⭐⭐): Use a declaration to add a
last(): T | undefinedmethod to the built-inArray<T>interface. Then call this method on an actual array, and consider why this requires a module declaration.