Posted at

Typescriptでブラウザ用ライブラリを作成する時に困ったこと


はじめに

Typescriptがスタンダードになりつつある流れを感じ、勉強がてら既存のライブラリを書き換えようと思ったら、なかなか苦労した話です。


困ったこと

既存のライブラリは、以下のような使い方をします。


use.js

(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ファイルに出力されます。


index.js

(() => {

function init(setting) {
// init処理
};

window.Library = window.Library || {
start: (setting) => {
init(setting);
},
};
})()



Typescriptで書いてみる

とりあえず、ほぼそのまま貼ってみました。


index.ts

(() => {

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なんてないとのことです。

そりゃそうなんですが、どうやって解決するのがググりました。

Typescriptで手っ取り早く外部ライブラリを使う

Interfaceでwindowを定義してやることでエラーが回避できるらしい。


index.ts

interface Window {

Lib: any;
}

(() => {
function init(setting: any) {
console.log(setting);
}

window.Lib = window.Lib || {
start: (setting: any) => {
init(setting);
}
}
})();


一応エラーがでなくなったので、これでコンパイルしてみると、問題なく動きました。

スクリーンショット 2019-07-23 19.55.20.png


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を指定しないように書き直してみました。


index.ts

class Lib {

init(setting: any) {
console.log(setting);
}
}

export default class {
static start = (setting: any) => {
const lib: Lib = new Lib();
lib.init(setting);
}
}


こんな感じに書き直して、コンパイルを実行。

これも問題なく動きました。

スクリーンショット 2019-07-23 20.10.36.png


まとめ

個人的に、コード内には、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);
}
}

スクリーンショット 2019-07-23 20.16.55.png

以上です。