やりたいこと
JavaScriptで書かれたコードをTypeScript化する方法です。
前提条件
WebStorm 2018.2で確認しています。
概要
まずはコンパイルできるようにすることが最優先です。 それから、TypeScriptらしく変えていくといいと思います。
手順
次に、tsconfig.jsonを作成します。
WebStormではデフォルトで以下のように作成されます。
自分が使っているのはGoogle Chrome拡張なので、
とりあえずes2017
にしています(2018でもいいかも)。
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true
},
"exclude": [
"node_modules"
]
}
(補足)後から知りましたが、allowJs(最後のSは小文字)を使うと、混在した環境でも問題ないみたいです。
次に、拡張子を.js
から.ts
に変えます。
WebStormではRefactor→Renameを選択します。
リファクタリングできないという警告が出ますが、Yesを押して進めます。
Compile TypeScript to JavaScript?
と聞かれるのでYesを選択します。
それからエラーを潰していきます。
TS2304: Cannot find name ‘xxx’
変数が見つからないときに発生します。
*.js
からは検索しないようなので、他のファイルを*.ts
に変更してみます。
TS2339: Property ‘xxx’ does not exist on type ‘yyy’
型の違いによるエラー
例えば以下のコードでエラーが出ます。
エラーメッセージはProperty 'value' does not exist on type 'HTMLElement'
const exportTextArea = document.getElementById('exportTextArea');
exportTextArea.value = lines.join("\n") + "\n";
これは、document.getElementById('exportTextArea')
で取得できるのが
HTMLTextAreaElement
なのに対し、
TypeScriptはHTMLElement
としか解決できないために発生したエラーです。
(HTMLで定義されているので分からないですよね)
こういうときはまず、as
を使ってキャストを行います。
(コンパイルを通すのが最優先)
const exportTextArea = document.getElementById('exportTextArea') as HTMLTextAreaElement;
インスタンス変数未定義によるエラー
例えば以下のようなコードです。
class BlockedSite {
constructor(item) {
this.url = item.url; // ここでエラーになる
}
}
こういうときは、明示的にインスタンス変数を定義します。
class BlockedSite {
url: string;
constructor(item) {
this.url = item.url; // ここでエラーになる
}
}
handlerの場合はややこしいので、一旦anyにしておきます。
JSONによるエラー
JSONの値を参照するときにコンパイルエラーになります。
const BlockedSitesRepository = {
loadData: async function () {
const items = await ChromeStorage.get({blocked: []});
...
for (const item of items.blocked) { // ここでエラー
...
}
}
...
}
こういうときは、interfaceを定義します。 anyは手抜きです。
interface BlockedSitesList {
blocked: any[];
}
const BlockedSitesRepository = {
loadData: async function () {
const items = await ChromeStorage.get({blocked: []}) as BlockedSitesList;
}
...
}
TS2451: Cannot redeclare block-scoped variable ‘xxx’
組み込みの変数とかぶっている場合に発生します。
自分はStorage
という変数名がエラーになりました。
おそらく、Web Storage APIのStorageインタフェースと 競合していたと思われます。
Storage → ChromeStorageに変更しました。
TS2554: Expected 1 arguments, but got 0.
引数の数が合わない場合です。 例えば以下のようにハンドラとしても使う関数に対し、 使わないパラメータをignoreとしてたのですが、これがまずかったようです。
this.mediator.editUrl()
// 定義
editUrl(ignore) {
}
これは定義側を直すのがいいと思います。