タイトルのとおりで、TypeScript をある程度やっている人なら当然のことかと思いますが。
interface の拡張
TS の interface って拡張できるじゃないですか。
interface Foo { bar: string } interface Foo { baz: number } /* // 結果 Foo: { bar: string baz: number } */
こんな感じで。
ライブラリの型定義
ライブラリの型定義ってできるじゃないですか。
declare module 'module-name' { interface Foo { bar: string } export default Foo } import Foo from 'module-name' /* // 結果 Foo: { bar: string } */
これらを組み合わせる
組み合わせるじゃないですか。
// type definition file declare module 'module-name' { interface Foo { bar: string } export default Foo } // application file import Foo from 'module-name' declare module 'module-name' { interface Foo { baz: number } export default Foo } /* // 結果 Foo: { baz: number } */
はい。
どうなってしまったのか
期待値
bar と baz がマージされて、両方ともをメンバーに持つ Foo インターフェースになる。
実際には
あとに定義したほうだけが適用されて、baz をメンバーに持つ Foo インターフェースになった。
どうしたらよかったのか
// type definition file declare module 'module-name' { interface Foo { bar: string } export default Foo } // application file import Foo from 'module-name' declare module 'module-name' { interface Foo { baz: number } // これがいらなかった // export default Foo } /* // 結果 Foo: { baz: number } */
解説(私見込み)
declare module
は namespace のようなものなので、その中で interface を定義した段階でマージされて export までされている状態になっているっぽいです。
無駄に export してしまったため、違うものと認識され(?)、後に定義したものが先に export したものを上書きしてしまったっぽいです。
まとめ
公式を見るというのと、ミニマル環境で納得できるまで試してみて、ちゃんと理解することが大事なんだなと再確認しましたね。
正直型定義ファイルは declare module 'module-name'
だけできれば最低限コードは書けるので、理解を後回しにしていたのが仇になりました。
まぁ今回完全に理解できたので余裕だわ!1111111
ちなみに
vue-property-decorator の Vue を拡張したくて。
Element-UI を入れたはいいものの、型定義がなくて this.$message
が使えなかったんですよね。