新しいことにはウェルカム

[技術] [電子工作] [ガジェット] [ゲーム] のメモ書き

TypeScriptのススメ




JavaScriptのプログラムを書く時はTypeScriptを使っています。

元々はJavaScriptを直接書いていたのですが、使いたかったReactのコンポーネントがTypeScriptで書かかれていたため、試しにTypeScriptで書いてみたのがきっかけでした。

結局そのコンポーネントは使わなかったのですが、TypeScriptが便利で、それ以来TypeScriptで書くようになりました。

TypeScriptとは?

TypeScriptとは、Microsoftが開発している言語で、JavaScriptにコンパイルされて使われる言語です。

JavaScript界隈では、AltJSという、それ単独では動かないが、それからJavaScriptに変換して利用される言語というものがあり、TypeScriptもAltJSの1つです。

どちらかと言うと言語というより、C言語のプリプロセッサみたいなもので、JavaScriptを使いやすくする言語拡張のようなイメージでしょうか。

TypeScriptにしてここが良かった

名前チェック機能

まずタイプミスが無くなって、実行時のエラーが激減しました。

例えば下記のような変数名・関数名のタイプミスがあったとします。

function test(){
    console.log("TEST_01");
}

function run_01(){
    let str = "TEST_02";
    console.log( strrrr );    // strrrrがタイプミス
}

function run_02(){
    testttt();    // testttt()がタイプミス
}
    
run_01();    // ここでエラーが表示されて終了
run_02();    // ここでエラーが表示されて終了

実行すると、タイプミスの箇所でエラーになり、実行はそこで終了するのですが、エラーになるのは実際にタイプミスの箇所を実行しようとした時です。

逆に言えば、タイプミスの箇所が呼ばれない限りプログラムはエラーにはならず動作し続けるので、一見正常に動作しているように見えます。

そして、プログラムが稼働してずっと後になってから、タイプミスの箇所が呼ばれた時に初めてエラーになり、そこでやっとタイプミスに気づきます。

一方TypeScriptは、名前に「Type」とついているように、JavaScriptに型・名前宣言を強要します。なので上記のタイプミスは、TypeScriptからJavaScriptへのコンパイルでエラーになるのですぐに分かります。

これのおかげでエラーが激減して、作業効率がずいぶん上がりました。

ダウングレード機能

次に、JavaScriptのバージョンを気にしなくてよくなり、最新のJavaScriptの言語仕様でプログラムが書けるようになりました。

ブラウザとそのバージョンによって、対応しているJavaScriptのバージョンが異なります。

ブラウザに対応できるよう意識しながらJavaScriptを書くのは大変なので、JavaScriptの開発界隈では、コードは最新のJavaScriptの言語仕様で書き、それをコンパイルしてダウングレードしたものを使ういとうことをよくやります。

そういったJavaScriptのダウングレードは「Bable」などを用いて行うのですが、TypeScriptも同様のダウングレード機能をそなえているので、TypeScriptを使えば、他の設定なしで最新のJavaScriptのバージョンでプログラムを書くことができます。

導入方法

  1. npmを使っているのでしたらnpm install -g typescriptでインストールされます。
    • バージョンを固定したい場合はnpm install --save-dev typescriptでpackage.json毎に決めることもできます
  2. ファイル拡張子は「.ts」で、実行コマンドは「tsc」です。
    • tsc test.tsと打つとコンパイルされ「test.js」が生成されます。
  3. TypeScriptを設定ファイルで設定することができます。設定ファイル名は「tsconfig.json」で「tsc」コマンドを実行するフォルダ配下に置きます。
    • tsconfig.jsonは無くても構いません

困った時の対処方法

設定

TypeScriptの設定は結構面倒で、正しいプログラムを書いているつもりでも、コンパイルエラーになることも多いかと思います。

tsconfig.jsonは「tsc」コマンドのオプションを設定ファイル化したものなので、オプションのドキュメントを参考にtsconfig.jsonを修正していきます。

外部モジュール

TypeScriptは型定義が必要なのですが、npmでインストールする外部モジュールはJavaScriptで記載されているので、コンパイル時に、そのモジュールのTypeScriptの定義が無いとエラーになることがあります。

そんな時は「@types/モジュール名」で定義がnpmで配信されている場合があるので、npm install --save-dev @types/モジュール名を試してみます。

「@types/モジュール名」を探してみたが無かった場合は、プログラム内で、モジュールを読み込んだ変数を「any」型にして定義が無くてもエラーにならないようにします。(例:const m:any = require(~);

React

慣れるまでは「create-react-app」でcreate-react-app my-app --scripts-version=react-scripts-tsとすると、React雛形のTypeScriptバージョンが作成されるので、それをベースに修正していくのがトラブルが少ないかと思います。参考(https://github.com/Microsoft/TypeScript-React-Starter

ちなみにTypeScriptでも中にJSXは書け、その場合の拡張子は「.tsx」となります。

困った時の「any」

型関連でエラーが発生する場合は

  • const test:any = 123;等、宣言時の型をanyにする。
  • console.log((test as any));等、使用箇所で型をanyにする。

にすると、とりあえずエラーは収まります。

個人的な利用方針

TypeScriptはJavaScriptを、必要な箇所だけ部分的に拡張した言語に過ぎないので、JavaScriptをそのままTypeScriptにしても動きます。(TypeScriptのコンパイル設定を緩めにする必要はありますが)

TypeScriptには、列挙型・インターフェース・Genericsなど、JavaScriptには無い言語仕様が色々追加されているのですが、あまりTypeScript固有の機能は使わず、素に近いJavaScriptになるようにしています。

TypsScriptは型定義が売りなので怒られそうですが、型定義・宣言もほとんど使わず、「any」型にしています。

では何のためにTypeScriptを使っているかというと、前述のタイプミスチェックのためで、このためだけにTypeScriptを使っているといってもオーバーではないくらい恩恵を受けています。

その他

JavaScriptを使っているが、最近TypeScriptが気になりかけている。という方でしたら、使ってみることをオススメします。

JavaScriptをそのままTypeScriptのコンパイラにかけて、タイプミスだけ検知するような使い方なら、ほとんど覚えることはないですし、それでもTypeScriptを使う価値は十分に得られるんじゃないかなぁと思います。

おまけ

TypeScriptはJavaScriptのように、書いて即実行ができず、ある程度お膳立てが必要です。

毎回準備するのは手間なので、下記のような雛形を作っておいてフォルダコピーして使っています。

TypeScriptソースは「src」フォルダに置くようにし、npm run testで「build」フォルダにJavaScriptが生成され実行します。

構造

  • フォルダ
    • src
      • test.ts
    • package.json
    • tsconfig.json

test.ts

console.log('test');

package.json

{
  "scripts": {
    "build": "tsc",
    "start": "node ./build/test.js",
    "test": "npm run build && npm run start"
  },
  "devDependencies": {
    "@types/node": "",
    "typescript": ""
  }
}

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "noImplicitAny": true,
        "allowUnreachableCode": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "build",
        "baseUrl": ".",
        "paths": {
            "*": [
                "node_modules/*",
                "src/types/*"
            ]
        }
    },
    "include": [
        "src/**/*"
    ]
}