TypeScript で window 直下にいろいろ生やしたりグローバル変数を定義する
TypeScript は開発に安定をもたらしてくれますが、たまにやりたいことがちょちょっとできずにハマることがあります。今日はそのひとつ、 window
オブジェクトにいろいろ生やしたいんだけどうまく生やせないあなたのための記事です。
ポイントは次のふたつです。
- tsconfig.json の
lib
に"DOM"
が指定されているかどうか window
の定義においてimport
/export
を使っているかどうか
tsconfig.json の lib
に "DOM"
が指定されているかどうか
tsconfig.json の lib
プロパティに "DOM"
が指定されているかどうかで書くべき内容が変わります。ご自身の tsconfig.json の中身を確認してみてください。 lib
プロパティがない場合は "DOM"
が指定されているものとして扱ってください。
DOM
あり
この場合、 interface のマージを使います。 lib
に "DOM"
が指定されている場合、 DOM に関する各種の定義が読み込まれるため、 Window
型および、この型を持つ ambient 変数 window
が存在するためです。
DOM
なし
こちらでは ambient 変数 window
を定義する必要があります。素のままでは何も定義が存在しないからですね。
window
の定義においてimport
/ export
を使っているかどうか
さてもうひとつの判断軸です。どちらかを使っている場合、 TypeScript はその定義があるファイルを module として認識します。複数の module で同名の定義があってもエラーとならないよう、それぞれの module は名前空間を持ちます。拡張するときはこの名前空間を指定してやらなければならないのですね。
module として定義する場合
window
は名前空間 global
を持って定義されますので、 declare global
を使って合わせてやる必要があります。
module として定義しない場合
この場合、特に考慮すべきことはありません。
パターン別実例
次のコードをコンパイルするために必要な定義例を、パターンごとに紹介します。
function main() { return window.myProp } main()
また、最低限の tsconfig.json
は次になります。lib
はパターンによって変更してください。
{ "compilerOptions": { "lib": ["ESNext", "DOM"], "baseUrl": "./", "paths": { "*": ["./src/@types/*"] } } }
パターンは次の 4 つです。
DOM なし |
DOM あり |
|
---|---|---|
module でない | 1 | 3 |
module である | 2 | 4 |
window
の定義は src/@types/window.d.ts
に書きましょう。
パターン 1
interface Window { myProp: number } declare var window: Window
declare var
で ambient な変数を宣言しているだけですね。
パターン 2
import MyProp from './my-prop' interface Window { myProp: number } declare global { var window: Window }
module となっているため、 window
が定義されている名前空間 global
以下に ambient 変数を宣言してください。
パターン 3
interface Window { myProp: number }
interface を拡張する書き方です。既存の window
に myProp
が追加されます。もちろん scrollTo
や addEventListner
など window
が持っているべき API も使用可能です。
パターン 4
import MyProp from './my-prop' declare global { interface Window { myProp: MyProp } }
こちらは名前空間をあわせてやっているだけで、パターン 3 と同様です。
注意点
パターン 1 およびパターン 2 について、 window
が持っているべき API を使いたい場合は自分で定義してあげましょう。こういった定義はあまり頻度が高くないと思いますが、 window
以外のグローバル変数を宣言する際も同様ですので参考にしてください。
まとめ
できるだけ ambient 宣言は使わないほうが良いと思うのですが、 window
についてはしょうがないところがあるのでご自身のパターンに最適な定義を使ってください。