TypeScriptのinterfaceとtypeは、オブジェクトの形を表すだけならどちらでも書けます。迷ったときは、宣言マージのように後から同名定義を拡張したいならinterface、UnionやTupleなどオブジェクト以外も一つの名前で表したいならtype、と考えると整理しやすくなります。単純なオブジェクト型では、チームの規約に合わせて統一することも重要です。
まず判断表で違いを確認する
| 判断ポイント | interface | type |
|---|---|---|
| オブジェクト型 | 得意 | 得意 |
| Union・Tuple・プリミティブの別名 | 不可 | 可能 |
| 同名宣言のマージ | 可能 | 不可 |
| 型の拡張 | extends | 交差型 & など |
| クラスのimplements対象 | 利用可能 | オブジェクト形状なら利用可能 |
『オブジェクト型ならinterface、それ以外はtype』と完全に二分できるわけではありません。TypeScriptは構造的型付けなので、両方で表せる領域が大きく重なります。違いが必要になる場面だけを押さえるのが実務的です。
同じオブジェクト型は両方で書ける
interface UserByInterface {
id: number;
name: string;
}
type UserByType = {
id: number;
name: string;
};
この例では、どちらもidとnameを持つオブジェクト型を表します。単純なデータ構造を定義するだけなら、書き味の差よりも既存コードの方針やチーム規約に合わせるほうが読みやすさを保てます。
用語解説:構造的型付け
型の名前ではなく、必要なプロパティやメソッドの形が一致しているかを中心に互換性を判断するTypeScriptの型システムの考え方です。
UnionやTupleはtypeで表す
type aliasはオブジェクト型だけでなく、UnionやTuple、プリミティブ型の別名も作れます。複数の候補をまとめる型ではtypeが自然です。
type Status = 'idle' | 'loading' | 'success' | 'error';
type Coordinate = [number, number];
type UserId = string | number;
interfaceはこのようなUnionそのものの別名には使えません。APIの状態や許可された文字列の集合を表すなら、typeの用途が明確です。
宣言マージが必要ならinterface
interfaceは同じ名前で複数回宣言すると、互換性のあるメンバーを一つのinterfaceへマージできます。ライブラリの型を拡張するDeclaration Mergingで重要になる性質です。
interface AppConfig {
apiUrl: string;
}
interface AppConfig {
timeout: number;
}
const config: AppConfig = {
apiUrl: '/api',
timeout: 3000
};
type aliasを同じ名前でもう一度宣言すると、重複した識別子として扱われます。『型を閉じておきたい』設計では、この違いを理解して選ぶ必要があります。
拡張はextendsと交差型で書き分ける
interface BaseUser {
id: number;
}
interface AdminUser extends BaseUser {
role: 'admin';
}
type BaseAccount = { id: number };
type AdminAccount = BaseAccount & { role: 'admin' };
どちらも既存の形を組み合わせられます。ただし、interfaceのextendsとtypeの交差型は、同名プロパティの衝突時などに扱いが同じとは限りません。複雑な合成では、エラー内容を確認しながら意図した型になるか検証してください。
実務では3つの基準で決める
- Union・Tupleなどオブジェクト以外を表すならtype
- Declaration Mergingや拡張可能な公開型を意図するならinterface
- 両方で書ける単純なオブジェクト型はプロジェクト内で書き方を統一する
『interfaceのほうが常に良い』『typeのほうが新しい』という優劣で考える必要はありません。表したい型の性質と、既存コードとの一貫性を優先してください。
関連するTypeScriptの型設計
TypeScriptをこれから導入する場合は環境構築の記事、定数から型を作って二重管理を減らしたい場合はkeyof typeofの記事がつながります。
(TypeScriptの開発環境を整えるについては『TypeScriptの始め方|Node.jsとVSCodeで学ぶ開発環境構築ガイド』をご参照ください)
(定数から型を自動生成するについては『TypeScript型定義自動化「keyof typeof」実践例と二重管理解消法』をご参照ください)
よくある疑問
interfaceとtypeは混在しても問題ない?
問題ありません。ただし同じ目的の型定義で書き方がばらつくとレビュー時の判断コストが増えるため、プロジェクトの方針を決めておくと読みやすくなります。
ReactのPropsはinterfaceとtypeのどちら?
単純なPropsオブジェクトならどちらでも表現できます。Unionを含む設計や既存の規約など、Props以外の要件で選んでください。
interfaceはUnionを表せない?
interface単体でUnion型そのものの別名は作れません。Unionを名前付きで表す用途にはtype aliasを使います。
まとめ
interfaceとtypeは、オブジェクト型では似た役割を持ちます。違いがはっきり出るのは、Union・Tupleなどを表す場面と、interfaceの宣言マージを使う場面です。まず型の性質を見て、両方で書けるならチーム内の一貫性で決めましょう。
迷っている型を一つ選び、Unionが必要か、宣言マージが必要か、既存規約はどちらかの3点で判断してみてください。