同名interfaceのマージで型が矛盾した原因と直し方
同じ名前のinterfaceを複数回宣言すると、TypeScriptはそれらを自動的に1つに合成します(宣言のマージ)。ただし同じプロパティ名を違う型で宣言すると、合成できずにエラーになります。
エラーメッセージの読み方
main.ts(5,3): error TS2717: Subsequent property declarations must have the same type.
main.ts- ファイル名
5- 行番号
3- 列番号 — この位置でtscが検査に失敗しました
TS2717- エラーコード — 検索するとTypeScriptの解説が見つかります
Subsequent property declarations must have the same type.- 内容 — 期待していたもの、または受け付けられなかったもの
このエラーが出る典型パターン
パターン1
1 interface Box { 2 width: number; 3 } 4 interface Box { 5 width: string; ^ 6 } 7 console.log("ok");
同名interfaceの宣言はマージされます。widthを最初はnumber、あとからstringと矛盾する型で宣言することはできません。
直し方: string を number にします。
パターン2
1 interface Item { 2 price: number; 3 } 4 interface Item { 5 price: boolean; ^ 6 } 7 console.log("ok");
priceの型は最初の宣言でnumberと決まっています。あとから同じ名前でboolean型として宣言すると矛盾します。
直し方: boolean を number にします。
パターン3
1 interface User { 2 active: boolean; 3 } 4 interface User { 5 active: string ; ^ 6 } 7 console.log("ok");
activeの型は最初の宣言でboolean型と決まっています。あとの宣言で違う型にすると合成できません。
直し方: string を boolean にします。
パターン4
1 interface Data { 2 count: number; 3 } 4 interface Data { 5 count: string; ^ 6 } 7 console.log("ok");
同名interfaceの宣言はマージされます。countを矛盾する型で再宣言することはできません。
直し方: string を number にします。
パターン5
1 interface Flag { 2 enabled: boolean; 3 } 4 interface Flag { 5 enabled: number ; ^ 6 } 7 console.log("ok");
enabledの型は最初の宣言でboolean型と決まっています。あとから違う型にすると合成できません。
直し方: number を boolean にします。
よくある誤解
「同じ名前で2回書いたら、後の宣言で上書きされるはず」という考えは誤りです。TypeScriptのinterfaceは上書きではなく合成(マージ)されるため、矛盾する型を持つプロパティがあるとその場でエラーになります。
実務での勘所
この自動合成は不具合ではなく、TypeScriptが意図的に用意している機能です。自分では手を加えられない外部ライブラリの型(グローバルなWindowインターフェースや、npmパッケージが提供する型など)に、後から独自のプロパティを追加したい場面で使われます。同じ名前でinterfaceを再度宣言するだけで、既存の型定義に新しいプロパティを継ぎ足せます。既存の宣言とプロパティの型が矛盾すると合成できずエラーになるのは、意図しない上書きで元のライブラリの型定義を壊さないための安全装置です。