



TypeScriptのinterfaceとtypeの違いとは?結論は2つだけ
TypeScript の interface と type の違いは、主にユニオン型などを書けるのが type、同じ名前で定義を追加できるのが interface という2点です。オブジェクトの形を表すだけなら、どちらを使ってもほとんど同じように動きます。

| interface | type | |
|---|---|---|
| オブジェクトの型 | 書ける | 書ける |
ユニオン型(A | B) | 書けない | 書ける |
| プリミティブ・タプル・関数型に別名 | 書けない(関数型は呼び出しシグネチャで可) | 書ける |
| 同じ名前で定義を追加(宣言のマージ) | できる | エラーになる |
| 継承・合成 | extends | &(交差型) |
基本の書き方:オブジェクトの型はどちらでも書ける
まず、ユーザー情報のような単純なオブジェクトを、両方の書き方で定義します。
interface UserI {
name: string;
age: number;
}
type UserT = {
name: string;
age: number;
};
const a: UserI = { name: "キノ", age: 30 };
const b: UserT = a; // 相互に代入できる2つの型は互いに代入できます。つまり、単純なオブジェクトなら interface と type のどちらを使っても動作に差はありません。
オブジェクトの型の基本は、こちらで解説しています。
違い1:typeはユニオン型が書ける
ユニオン型は「このうちどれか」を表す型です。type では、リテラルを | でつないで使えます。
type Status = "success" | "error" | "loading";
function showMessage(status: Status) {
console.log(status);
}
showMessage("success");
showMessage("done");// Argument of type '"done"' is not assignable to parameter of type 'Status'.Status に含まれない "done" を渡すと、コンパイル時にエラーになります。この「選択肢を限定する」書き方は interface ではできないため、ユニオン型が必要なら type を使います。
プリミティブ型やタプル、関数型に別名を付けるときも type を使います。
type Id = string | number;
type Point = [number, number];
type Handler = (event: string) => void;
interface Props {
onClick: (event: string) => void;
}
const p: Point = [1, 2];違い2:interfaceは同じ名前で定義を追加できる
interface は、同じ名前で複数回書くと、定義が自動的にひとつにまとまります。これを宣言のマージ(declaration merging)と呼びます。
interface User {
name: string;
}
interface User {
age: number;
}
const u: User = { name: "キノ", age: 30 }; // 2つがマージされるtype で同じことをすると、エラーになります。
type User = {
name: string;
};
type User = {
age: number;
};// Duplicate identifier 'User'.この性質は、すでにある型へプロパティを足したいときに役立ちます。たとえばブラウザの Window にプロパティを追加する場合です。
declare global {
interface Window {
appName: string;
}
}
window.appName = "kinoblog";一方で、意図せず同名の interface を書くと、エラーにならずにマージされる点には注意が必要です。
継承の書き方の違い:extendsと交差型
既存の型を拡張するとき、interface は extends、type は交差型(&)を使います。
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
type Cat = Animal & { color: string };
const d: Dog = { name: "ポチ", breed: "柴" };
const c: Cat = { name: "タマ", color: "白" };どちらも「Animalの内容を引き継いで、プロパティを足す」という結果は同じです。TypeScript公式ドキュメントには、extends を使った interface のほうが、交差型の type よりコンパイラの処理が速いことが多いと書かれています。
ジェネリクスでも使える:どちらも型引数を受け取れる
interface も type も、ジェネリクスで型引数を受け取れます。この点は使い分けの理由になりません。
type Response<T> = { data: T; status: number };
interface Box<T> {
value: T;
}
const r: Response<string> = { data: "ok", status: 200 };
const bx: Box<number> = { value: 1 };実務での使い分け:迷ったらinterface、ユニオンならtype
TypeScript公式ドキュメントでは、多くの場合どちらを選んでも構わず、迷ったら interface を使い、type の機能が必要になったら type を使う、という目安が示されています。
| 場面 | おすすめ |
|---|---|
| オブジェクトの形を表す | どちらでもよい(チームの規約に合わせる) |
| ユニオン型・リテラル型の組み合わせ | type |
| タプル・関数型・プリミティブの別名 | type |
| 既存の型にプロパティを追加(ライブラリの型の拡張など) | interface |
| Reactコンポーネントのprops | どちらでもよい(プロジェクト内で統一) |
もっとも大切なのは、プロジェクト内で書き方を統一することです。「オブジェクトは interface、それ以外は type」のように、ルールを決めておくとレビューで迷いません。
公式ドキュメントの比較は、こちらにまとまっています。
よくあるエラーと対処
1. Duplicate identifier ‘User’
type で同じ名前を2回定義したときのエラーです。名前を変えるか、追加したいなら interface に変更します。
2. Argument of type ‘”done”‘ is not assignable to parameter of type ‘Status’
ユニオン型に含まれない値を渡したときのエラーです。選択肢に追加するか、渡す値を直します。
3. 型アサーションで型を合わせたくなったとき
型が合わないからと as で押し切ると、実行時のエラーを見逃しやすくなります。先に型定義側を見直してください。
よくある質問
Q. interfaceとtype、初心者はどちらを使えばいいですか?
A. まずは type でも interface でも構いません。ユニオン型が必要な場面で type、迷ったら interface という目安で十分です。大切なのはプロジェクト内で統一することです。
Q. 実務ではどちらが多いですか?
A. プロジェクトの規約によって異なります。Reactのpropsでもどちらも使われており、片方に決まっているわけではありません。
Q. interfaceでユニオン型は書けませんか?
A. interface そのものでは書けません。ただし、type で作ったユニオン型を、interface のプロパティの型として使うことはできます。
Q. パフォーマンスに差はありますか?
A. 公式ドキュメントでは、extends を使った interface は交差型の type よりコンパイラに有利なことが多いとされています。ただし、小規模なアプリで気にする必要はほとんどありません。
まとめ:TypeScript interfaceとtypeの違いのおさらい
- オブジェクトの型だけなら、interface と type はほぼ同じ
- ユニオン型・タプル・関数型の別名は type で書く
- 同じ名前で定義を追加(宣言のマージ)できるのは interface だけ
- 継承は interface が
extends、type が交差型(&) - 迷ったら interface、type の機能が必要なら type。プロジェクト内で統一する
型注釈の基本から整理したい方は、こちらもあわせてどうぞ。











