はじめに
Typescriptがスタンダードになりつつある流れを感じ、勉強がてら既存のライブラリを書き換えようと思ったら、なかなか苦労した話です。
困ったこと
既存のライブラリは、以下のような使い方をします。
(function(){
// ライブラリの処理
// この中でwindow.Libraryを定義
})();
var setting = {
text: "text",
num: 1
};
window.Wapper = window.Wapper || {
start: function(setting) {
window.Library.start(setting);
}
};
なぜこの様な使い方なのかは、様々な事情があるので、割愛します。
ブラウザのwindowオブジェクトにプロパティを追加したいのですが、typescriptの場合、どのように書けばいいかわからなかったので、色々試してみました。
バージョン
typescriptのバージョンは、3.5.3です。
既存ライブラリの書き方
既存ライブラリは、ES2015で書かれていて、babel+webpackで最終的に1ファイルに出力されます。
(() => {
function init(setting) {
// init処理
};
window.Library = window.Library || {
start: (setting) => {
init(setting);
},
};
})()
Typescriptで書いてみる
とりあえず、ほぼそのまま貼ってみました。
(() => {
function init(setting: any) {
console.log(setting);
}
window.Lib = window.Lib || {
start: (setting: any) => {
init(setting);
}
}
})();
以下、エラーで怒られました。
Property 'Lib' does not exist on type 'Window'.ts(2339)
WindowにLibなんてないとのことです。
そりゃそうなんですが、どうやって解決するのがググりました。
Interfaceでwindowを定義してやることでエラーが回避できるらしい。
interface Window {
Lib: any;
}
(() => {
function init(setting: any) {
console.log(setting);
}
window.Lib = window.Lib || {
start: (setting: any) => {
init(setting);
}
}
})();
一応エラーがでなくなったので、これでコンパイルしてみると、問題なく動きました。
webpackとの兼ね合い
一応、上記の方法でwindowオブジェクトにプロパティを追加できたのですが、気になったことが。
webpackには、libraryというオプションがあって、これを使うと同様にwindowオブジェクトにプロパティを追加できます。
module.exports = {
mode: 'production',
entry: './src/index.ts',
output: {
path: `${__dirname}/lib`,
filename: 'index.js',
library: "Lib",
libraryExport: "default",
libraryTarget: "umd"
},
・・・
これも有効にした場合、どのように動くのかやってみました。
結果は、問題なく動いたんですが、たぶん、コードでwindowに追加されているので、webpackの設定は、関係なくなっているような気がします。
そこで、コード内でwindowを指定しないように書き直してみました。
class Lib {
init(setting: any) {
console.log(setting);
}
}
export default class {
static start = (setting: any) => {
const lib: Lib = new Lib();
lib.init(setting);
}
}
こんな感じに書き直して、コンパイルを実行。
これも問題なく動きました。
まとめ
個人的に、コード内には、windowの記述を書かないで、webpackの設定でプロパティを追加する方法の方がスマートなのかなと思いました。
他にも方法があるのかもしれないのですが、一旦、やりたいことはできたので、よかったです。
後、引数をany
にしていますが、実際にはちゃんと型書いてます。any
は使わないようにしてます。
おまけ
webpackのlibrary設定ですが、コード内にexport defalt
の記述があるクラスが存在しないとうまく動かなかったです。
class Lib {
init(setting: any) {
console.log(setting);
}
}
export class Main {
static start = (setting: any) => {
const lib: Lib = new Lib();
lib.init(setting);
}
}
以上です。