Javascriptのプロジェクトに段階的にTypescriptを導入したい。

Javascriptが標準のプロジェクトにおいて、Typescriptに移行したいとする。

一気に移行するのはリスクも大きいし、成功する気がしない。 なので、現実的には、Javascriptをできるだけ小さくTypescriptに切り出すのを繰り返して、段階的に移行していくのがよいと思う。

段階的な移行の仕方を2ステップで説明してみる。 2ステップで説明はするが、それぞれのステップを一度に実施するわけではなくて、小さく繰り返して実施することを想定している。

ステップ1

まずは、モジュールバンドラを使わない環境を前提とするが、以下を守れば、部分的にTypescriptを切り出すことができる。

  • Javascriptからは、Javascript or Typescriptのどちらも呼び出せる。
  • Typescriptからは、Typescriptしか呼び出さない。

要するに終端側のコードをTypescript化していき、少しずつTypescriptにできる範囲を広げていく。

ちなみに、Typescriptの依存関係はimportではなく、トリプルスラッシュで記述する。

別ファイルの依存関係を読み込む場合は以下。

/// <reference path="./helper.ts" />
/// <reference types="@types/jquery" />

ステップ2

ステップ1の制約を外す。

  • Typescriptからも、Javascriptを呼び出せるようにする。

節操なくTypescriptにするのではなく、ステップ1とは逆に起点側のコードをTypescript化していく。

TypescriptからJavascriptを呼び出そうとすると、型情報がないのでエラーが起きる。 一つの案としては、アダプタになるクラスを用意し、そのクラスには型定義ファイル(.d.ts)を作成し、 そのクラスからのみJavascriptを呼び出せるようにする。

例えば以下のようなアダプタになるクラスの型定義(hello.d.ts)は以下。

declare class Hello {
    constructor();
    execute(): void;
};
export default Hello;

Javascriptの実装(hello.js)は以下。

export default class Hello {
  constructor() {
    
  }
  execute() {
    console.log('Execute JS!');
  }
}

アダプタを呼び出すTypescriptのコード(main.ts)は以下。

import Hello from "./hello";

var hello = new Hello();
hello.execute();

モジュールバンドラの導入

モジュールバンドラを導入するには、基本的にはステップ2の実施が必要。

理由は、モジュールバンドラで生成されるJSがグローバルを汚染しないので、基本的に外部から呼び出せないため。 (設定次第で一部関数やクラスのみグローバルに公開することもできたりする?)

モジュールバンドラの導入ができればサードパーティーのモジュールの導入が容易になるなど、状況によっては大きな利点が得られる。

ただし、tsファイル内でグローバル変数を使っている場合は、モジュールバンドラを導入する前に、グローバル変数を排除しておく必要がある。モジュールバンドラを使っていなければ、各*.tsファイルの直下で宣言している変数はグローバル変数だったが、モジュールバンドラを導入するとモジュール内に閉じ込められるためである。

余談

それなりに知識と経験がないと、思わぬところで問題が発生して詰まってしまう可能性は非常に高い。実施する場合は慎重に実施する必要がある。

レガシーな環境で苦労しつづけるのがよいか、血を流しながら移行していくのがよいかはなんとも言えない。。。