TypeScript

Typescriptコンパイル時にDuplicate Identifierと出た時の対処法

はじめに

TypescriptのHandbookのInterfaces Extending Classesを写経していたとき、次のコードをtsc main.tsでコンパイルしようとしたところエラーが発生。

main.ts
class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {

}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    select() { }
}

class Location {

}

対策

以下のようにtsclibオプションをes5es6にすることで解決。

tsc --lib es5 main.ts

何が起きているのか

コンパイル時のエラーは次の通り。

$ tsc main.ts
../../.config/yarn/global/node_modules/typescript/lib/lib.d.ts(11522,11): error TS2300: Duplicate identifier 'Location'.
../../.config/yarn/global/node_modules/typescript/lib/lib.d.ts(11538,13): error TS2300: Duplicate identifier 'Location'.
../../.config/yarn/global/node_modules/typescript/lib/lib.d.ts(18989,13): error TS2300: Duplicate identifier 'Image'.
main.ts(18,7): error TS2300: Duplicate identifier 'Image'.
main.ts(18,7): error TS2420: Class 'Image' incorrectly implements interface 'SelectableControl'.
  Property 'state' is missing in type 'Image'.
main.ts(22,7): error TS2300: Duplicate identifier 'Location'.

下から2つ目のエラーはImageクラスがSelectableControlインターフェースを実装できていないということで予想通りのエラーだが、他のエラーは「LocationやImageが既に宣言されている」という内容になっている。
どうやらtscはデフォルトでnode_modules/typescript/lib/lib.d.tsを読みに行っているらしい。対応する行を確認すると確かに宣言されていた。

node_modules/typescript/lib/lib.d.ts
// 18989行目
declare var Image: { new(width?: number, height?: number): HTMLImageElement; };

// 11522行目
interface Location {
....
}

公式ドキュメントによるとtscはデフォルトで--lib es5,dom,scripthostで走るようで、domに関する宣言ファイルを読み込んでいるため上のようなエラーが出てしまっているようだ。 1

まとめ

ドキュメントをしっかり読んでデフォルトオプションには気をつけたいところだ。


  1. 正確には--targetES5の場合に--libes5,dom,scripthostになります。デフォルトの--targetES3なので、--targetES5の場合と同じ挙動なのかわかりませんが、domはES3の場合にも含まれているようです。