interfaceとtypeの使い分けです。JavaScriptは元々そこそこ書けていたので、「型を書く」という発想自体には早く慣れました。ただ、その分「なぜ同じようなことができる書き方が2種類あるのか」がかえって気になり、調べるのに時間がかかりました。この記事では、実際のコード例をもとに違いを整理します。
JavaScript経験者ほど「どっちでもよくない?」と感じる理由
JavaScriptにはそもそも型という概念がないので、TypeScriptで初めて型を書く人にとっては、interfaceもtypeも「オブジェクトの形を決めるもの」という点では同じに見えます。
// interfaceの場合
interface User {
name: string;
age: number;
}
// typeの場合
type User = {
name: string;
age: number;
};実際、単純なオブジェクトの形を定義するだけなら、どちらを使っても動作にほぼ差はありません。「どっちでもいい」という感覚は、実は間違っていません。差が出るのは、もう少し複雑なことをしたいときです。
違い1:typeはユニオン型が書ける
JavaScriptで「この値は”success”か”error”のどちらか」を表現したいとき、文字列を直接比較するくらいしか方法がありませんでした。TypeScriptのtypeを使うと、これを型として表現できます。
type Status = "success" | "error" | "loading";
function showMessage(status: Status) {
// statusには"success"|"error"|"loading"以外は渡せない
}これはinterfaceではできません。オブジェクトの形ではなく「いくつかの選択肢のどれか」を表したい場合は、typeを使う一択になります。API通信の状態管理などでよく出てくる書き方なので、React学習を進める中で最初に「typeじゃないとダメだ」と実感したのがこの場面でした。
違い2:interfaceは同じ名前で定義を追加できる
逆にinterfaceだけができることもあります。同じ名前のinterfaceを複数回書くと、自動的にマージ(統合)されます。
interface User {
name: string;
}
interface User {
age: number;
}
// User型は { name: string; age: number } として扱われるtypeで同じことをすると、単純にエラーになります。
type User = { name: string };
type User = { age: number };
// Error: Duplicate identifier 'User'.この「宣言のマージ」は、既存のライブラリの型定義を拡張したいときなどに使われる仕組みで、普段の実装ではあまり出番はありませんが、「なぜかtypeで同じコードを書くとエラーになる」と最初に混乱したポイントだったので載せておきます。


結局、実務ではどう使い分ければいいのか
調べていく中で分かったのは、「絶対的な正解がある」というよりは、次のような目安で使い分けられていることが多いという点です。
- オブジェクトの形を定義するだけならinterface:Reactのpropsの型など、素直な構造を表すときに読みやすい
- ユニオン型や複雑な組み合わせが必要ならtype:状態管理やAPIレスポンスの型など、「AかBか」を表現したいとき
実際のプロジェクトでは、チームやライブラリごとに方針が決まっていることも多いので、「自分がどちらを使うか」より「そのプロジェクトのコードがどちらに寄せているか」を見て合わせる方が実務的だと感じています。JavaScriptで「なんとなく動くコード」を書けていた分、TypeScriptでは逆に「なぜこの書き方を選ぶのか」を言語化する練習になっている、というのが今のところの実感です。

