Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. TypeScript Dictionary
  3. interface

interface

Since: TypeScript 1.0(2014)

Defines the "shape" of an object — that is, what properties it has. You can use an interface as a contract that a class must implement, or as the type for function arguments and return values.

Syntax

interface InterfaceName {
	propertyName: type;
	propertyName?: type; // Optional property (can be omitted)
	readonly propertyName: type; // Read-only property
}

interface NewName extends ExistingName {
	additionalProperty: type;
}

Syntax Reference

SyntaxDescription
interface Name { ... }Creates a type definition for an object. Specifies property names, types, and modifiers.
propertyName?: typeAn optional property. If omitted, its value is undefined.
readonly propertyName: typeA read-only property whose value cannot be changed after initialization.
extendsInherits and extends another interface. You can extend multiple interfaces at once.
Declaration mergingIf you define an interface with the same name more than once, the definitions are automatically merged into one.
implementsDeclares that a class implements an interface. The class is required to implement all properties and methods defined in the interface.

Sample Code

interface User {
	id: number;
	name: string;
	email?: string; // Optional property.
	skill?: string; // Optional property.
	readonly createdAt: Date; // Read-only property.
}

const user: User = {
	id: 1,
	name: "member_1",
	skill: "data_analysis",
	createdAt: new Date(),
};
console.log(user.name); // Outputs "member_1".
// user.createdAt = new Date(); // Error: cannot reassign a readonly property.

// Extend an interface to add more properties.
interface AdminUser extends User {
	role: "admin" | "superadmin";
	permissions: string[];
}

const admin: AdminUser = {
	id: 2,
	name: "Admin",
	createdAt: new Date(),
	role: "admin",
	permissions: ["read", "write", "delete"],
};
console.log(admin.role); // Outputs "admin".

// Implement interfaces in a class.
interface Printable {
	print(): void;
}
interface Serializable {
	serialize(): string;
}

class Document implements Printable, Serializable {
	constructor(private content: string) {}

	print(): void {
		console.log(this.content);
	}

	serialize(): string {
		return JSON.stringify({ content: this.content });
	}
}

const doc = new Document("Hello, TypeScript!");
doc.print(); // Outputs "Hello, TypeScript!".

// Declaration merging: interfaces with the same name are merged automatically.
interface Config {
	host: string;
}
interface Config {
	port: number; // Merged with the previous Config interface automatically.
}
const config: Config = { host: "localhost", port: 3000 };
console.log(`${config.host}:${config.port}`); // Outputs "localhost:3000".

Running the above produces the following output:

npx ts-node ts_interface.ts
member_1
admin
Hello, TypeScript!
localhost:3000

Overview

interface is the primary way to define the "shape" of an object in TypeScript. By requiring objects to have specific properties and methods, you can guarantee the structure of values passed as function arguments and verify that a class has implemented all required members.

A distinctive feature of interfaces is declaration merging: if you define an interface with the same name in multiple places, TypeScript automatically combines them into a single definition. This is especially useful when you want to extend a library's type definitions from outside (type augmentation).

Both interfaces and type aliases can define object types, but interfaces work well with classes and support inheritance and declaration merging. Using interfaces for object structure definitions is the common convention.

Why Both interface and type Exist

TypeScript provides two ways to describe the shape of an object: interface and type aliases. Both features exist for historical reasons, and their roles differ in subtle ways.

Historical Background

Originally, only interface existed (TypeScript 1.0, 2012). It was designed as a direct port of the "interface" concept from Java and C# — a traditional object-oriented programming (OOP) tool for defining the contract a class must fulfill.

Later, the need arose to handle union types (types that accept multiple alternatives, such as string | number), aliases for primitive types, tuples, conditional types, and more. The type alias was added as a mechanism for giving a name to anything. Because the existing interface could not be removed, both features remained side by side.

The TypeScript design team has publicly acknowledged that both exist for historical reasons, and there are no plans to merge them. As a result, users need to understand the role of each and choose accordingly.

An Analogy from C

For developers familiar with C, think of interface as similar to struct (a named structure) and type as similar to typedef (a type alias).

CTypeScriptCommon Trait
structinterfaceDeclares a structure (a collection of properties). Can be redeclared with the same name to merge definitions.
typedeftypeGives an alias to anything. Redeclaration with the same name is not allowed.

Just as C's struct Name { ... } "defines a named structure" while typedef "attaches a short alias to an existing type," the two TypeScript features follow a similar division of responsibility.

Declaration Merging (Available Only with interface)

When you declare an interface with the same name in multiple places, TypeScript automatically merges them into one. This feature, called declaration merging, is useful when you want to extend the types of an external library, and it is something type cannot do.

A Typical Real-World Example — Extending Express Types

Consider a case where you want to attach user information extracted by an authentication middleware to the request object (Request) in Express (a Node.js web framework). You cannot rewrite Express's own type definitions, but with declaration merging you can add fields from your own project.

// Declare this in a file such as 'types/express/index.d.ts'.
import "express";

declare module "express" {
	interface Request {
		userId?: string; // User ID extracted from the JWT after authentication.
		organizationId?: string; // Organization ID extracted from the JWT after authentication.
	}
}

// From here on, req.userId / req.organizationId can be used type-safely in any route handler.
import express from "express";
const app = express();

app.get("/profile", (req, res) => {
	console.log(req.userId); // Type-checks pass because userId exists on interface Request.
	console.log(req.organizationId);
	res.json({userId: req.userId});
});

Trying to achieve the same thing with type would require rewriting Express's own type definitions, which is practically impossible. Extending library types is the exclusive domain of interface.

How Declaration Merging Works

Declaration merging applies not only to properties but also to method signatures. However, if the same property appears with conflicting types in two declarations, a compile error is raised.

// OK: adding different properties.
interface Config {
	host: string;
}
interface Config {
	port: number;
}
const config: Config = {host: "localhost", port: 3000}; // Both are required.

// NG: same property name with conflicting types.
interface BadConfig {
	value: string;
}
interface BadConfig {
	value: number; // Error: type conflicts with string.
}

When to Choose interface

As a practical guideline, choose interface in the following situations.

  • Extending library types (declaration merging is required). Use this when you need to add your own fields to external library types such as Express, React, or Fastify.
  • Defining contracts for classes to implement (works well with the implements keyword). Use this when designing with an interface-driven, OOP-style architecture.
  • Defining plain object structures (convention). For types like ChatData or DashboardData that represent "the shape of data," the TypeScript community convention leans toward interface.

When in doubt, choosing interface covers about 80% of situations without issue. Switch to type only when you need something that interface cannot express — such as union types, primitive aliases, tuples, or conditional types. For details, see type (type alias).

If you find any errors or copyright issues, please .