TypeScriptのtypeとinterfaceの違いと使い分け方まとめ
はじめに
TypeScriptを学んでいて、typeとinterfaceの使い分けについて悩んだので、調べて記事にしてみました。
TypeScriptを使っている人の役に立てれば幸いです。
この記事の対象者
・TypeScriptを学び始めた人
・typeとinterfaceの使い分け方がわからない
結論
| 特徴 | type | interface |
|---|---|---|
| 扱える対象 | プリミティブ型・ユニオン型・オブジェクト型など幅広い | オブジェクト型のみ |
| 拡張性 |
& で合成(クローズド) |
宣言マージ可能(オープンエンド) |
| 歴史 | 後から追加された機能 | 初期から存在 |
| 実務での注意点 | 柔軟だが何でも書けて混乱しやすい | マージで意図しない拡張が起こる可能性 |
結論、TypeScript公式に従うなら、「基本どちらでもよい。もしくは基本interfaceを使い、typeが必要な場面が出てきたらtypeを使う。」です。
interfaceの特徴
interfaceはオブジェクト型専用の仕組みで、オープンエンド(宣言マージ可能) という特徴を持ちます。
特徴まとめ
・宣言マージが可能(オープンエンド)
・オブジェクト型にしか使えない。
「オープンエンド」とは、同じ名前のinterfaceを複数回宣言してもエラーにならず、自動的に統合される仕組みのことです。
下記のコード例を見てみます。
※TypeScript公式から引用
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = { height: 5, width: 6, scale: 10 };
上記の例では、Box型が自動的にマージされ、height,width,scaleをすべて持つオブジェクトを表せるようになっています。
このように簡単に型をマージできるというのは、特に外部ライブラリに自分のプロパティを追加する際に便利だと思います。しかし、簡単にマージできるというのは、裏を返せば割と規模の大きめのプロジェクトで考えてみると、他の人が定義したinterfaceを意図せず上書きしてしまいかねないという悪い側面も持ち合わせているように思えます。
また、typeが登場する2014年以前では、interfaceしか存在せず、慣例的にinterfaceを多く使っているプロジェクトも多いようです。
typeの特徴
typeは型に別名をつける仕組みで、柔軟に使えるのが特徴です。
特徴まとめ
・どんな型にも使える(プリミティブ / オブジェクト / ユニオン / タプルなど)
・合成(拡張)ができる(&で他の型と組み合わせ可能)
・閉じている(一度定義した型に後からプロパティを追加できない)
・歴史的には新しい(TypeScript初期には存在せず、2014年に導入)
typeでは、次のようにプリミティブの型に別名を与えることも一応可能です。
type BarString = string;
const bar: BarString = "bar";
また次の例は、既存のUser型を&で合成して拡張する方法です。
同じ名前でtype Userを再宣言するとコンパイルエラーになります(=閉じていることを示しています)。
type User = {
id: number;
name: string;
};
type UserWithEmail = User & { email: string };
const u: UserWithEmail = {
id: 1,
name: "Alice",
email: "alice@example.com"
};
結論どっちを使う?
主な違いは、typeは新しいプロパティを追加するために再度オープンできないのに対し、interfaceは常に拡張可能であることです。
「開いて拡張できるかどうか」 が最大の違いとなっています。
TypeScript公式の見解
TypeScript公式で、以下の記述がありました。
For the most part, you can choose based on personal preference, and TypeScript will tell you if it needs something to be the other kind of declaration. If you would like a heuristic, use interface until you need to use features from type.
大部分の場合は、個人の好みに基づいて選んで構いません。TypeScript は、もし別の種類の宣言が必要であればそれを教えてくれます。
もし目安としての指針が欲しいなら、type の機能が必要になるまで interface を使いなさい。
ということで、公式に従うなら大部分の場合、interfaceとtypeは好みで選んでよいとのことです。
また、普段はinterfaceをデフォルトで選び、typeでしかできない特殊な表現が必要なときだけtypeを使うというのが結論でした。
とある書籍の見解
しかし、私が参考にしたプロを目指す人のためのTypeScript入門という書籍から引用すると、
ほとんどの場合、interface宣言はtype文で代用可能です。しかもtype文のほうがより多くの場面で使えるので、interface宣言は使用せずにtype文のみを使うという流儀もあるようです(筆者もそうです)。
とのことで、type文を押しているような記述が見られました。
私(筆者)の見解
私はというと、お恥ずかしながら実務でTypeScriptを使ったことがないので何とも言えないのですが、type文のほうを支持したいと思います。
どちらを使ってもよいというのは公式の見解と同意見なのですが、interface文特有のオープンエンドが、大規模開発の時に悪さをするような気がするというのが一番の理由です。
しかし、結局そのチームによって使い方統一するというのが一番いいのかもしれないですね。
参考
・TypeScript公式
・interfaceとtypeの違い、そして何を使うべきかについて
・サバイバルTypeScript
・プロを目指す人のためのTypeScript入門
Discussion