最近の開発で、Webアプリのプロトタイプを作る仕事がありました。今も続けていますが。
その中で、ほとんどWebのフロントエンドをやったことがない人間(筆者)が、TypeScript
を使ってみたので、その感想と紹介をしてみます。
認識違いはありそうなので、誤り等はご容赦ください。
筆者経験(担当時点)
- バックエンド(サーバーサイド)は経験あり。Web APIを作れと言われたら作れる
- フロントエンドは、ブラウザはほぼ経験なし。
WPF
はかなりいじっているし、UWP
に関してもそれなりに知っている - いわゆる
MVCフレームワーク
に基づいたWebアプリの仕組みについては理解している
既存のフレームワークだけだと、動的ページを作るのが難しいことは知っている、ということ
経緯
条件を複数指定して、検索結果を表示する画面を作る必要がありました。見た目はbootstrap4
で繕っています。
単純なものであれば、固定入力欄を用意して、フォームでリクエスト飛ばして、ページ遷移させて結果を表示するという形で実現できます。一度それで作りました。
しかし、条件自体を追加しながら検索したい、という要望が発生する*1のは容易に想像できるため、その機能を前提とした作りに挑戦しよう、と思いました。
そこで、
- 検索条件を
JSON
に詰め込んで、リクエストとしてサーバーに送る - 検索結果をレスポンスで送り返す
- そのままページ遷移させずに表示
という作りに挑戦してみました。
クソ下手な絵(ペイント3D作)
…慣れた人にとっては大したことはないんですよねきっと。
仕組み上、どう考えてもJavaScript
を使う必要がありますが、あまり良い印象を持っていないため、TypeScript
で挑戦してみよう、というのが、今回使った経緯です。
余談ですが、バックエンドはDjango
で、Django-Rest-Framework
を使ってWeb APIを作りました。それはそれで苦労しましたが、仕組みそのものは理解していたので、大したことはなかったです。
このときに、検索処理をフォームからでもREST API
経由でも使えるように、Repository
等を利用して処理を一つにしたのは、まあいいでしょう。
TypeScript使用準備
開発にはVisual Studio Code
を使用しています。
が、そもそもTypeScript
で作ったスクリプトを動かすには、JavaScript
に変換(トランスパイル)する必要があります。
typeScript
のコンパイラを簡単に使うには、まずNode.js
をインストールし、一緒に入ってくるnpm
を使って
npm install -g typescript
とすればよいです。*2
tsconfig.json作成
コンパイル自体は、上記のようにインストール後に
tsc index.ts
のようにファイルを指定すると行えます。
ただ、実際に開発する場合は、生成後のJavaScript
ファイルを置く場所を変更したり、TypeScript
自体をデバッグできるようにしたり、フォルダ内にあるスクリプトを一括でJavaScript
に変更したい等あります。
そのときは、TypeScript
の開発フォルダで
tsc --init
と入力し、tsconfig.json
を生成します。
私が有効にした設定は、
{ "compilerOptions": { //途中省略 "declaration": true, "sourceMap": true, "outDir": "", //実際にはJavaScriptの出力先を指定 //以下省略 } }
という感じです。これをやった後は、tsconfig.json
があるフォルダでtsc
コマンドを実行すると、設定したとおりにJavaScript
が生成されます。*3
単にWebページから呼び出すだけなら、この程度の環境設定で使えるようになります。
TypeScriptのコーディング
これは、ここ良かったなぁ、と思ったところを挙げていきます。
型ヘルプ(Intellisense)が充実している
これは非常に大きかったです。
例えば、JavaScript
で
const btn = document.getElementById('search')
という処理を書くと、見た目上、btn
はHTMLElement
として扱われますが、実際は要素に応じた型です。そして、開発者にとっては、ID
を指定した時点で、それが何なのかわかっています。
そこで、TypeScript
では、
const btn = <HTMLButtonElement>document.getElementById('search');
のように書くことでキャストされ、ソース上要素型を明示できます。
他にも、動的に要素を作成する場合、
values.forEach(v => { const item = document.createElement("a"); item.classList.add("list-group-item", "list-group-item-action", "list-group-item-primary"); item.href = v.url.href; item.text = v.name; item.target = "_blank"; resultElem.appendChild(item); });
というソースがある場合に、
というように、作っているのはAnchor要素だよ、というのを判断して出してくれます*4。
筆者のようなJavaScript
初心者でも、どの型にどのプロパティがあるのかはっきりわかることで、
- ミスを減らせる
- 使うべきプロパティが一覧化されるため、名前を調べなくてよい(要素名を知っている前提)
- 勘違いを減らせる
というような効果が見込めます。
まあ、document.createElement
だと、JavaScript
であっても型解釈ぐらいはやってくれますが…getElementById
では恩恵にあずかれます。
慣れ親しんだクラスが使える
これは、C#
やJava
、Python
等に慣れ親しんだ人にとっては、大きすぎる利点でしょう。
JavaScript
では、prototype
というものを使ってクラスを表現*5していましたが、これが個人的には取っつき辛い部分でした。
TypeScript
では、最初からクラス構文が用意されているので、大変分かりやすいです。
当然、メソッドの引数はany
ではなく型指定されるので安心です。
たとえば、TypeScript
のクラスとメソッド
class SearchChanger { public Show(samples: Array<Sample>) { //処理 } }
というものがあると、JavaScript
では
var SearchChanger = /** @class */ (function () { SearchChanger.prototype.Show = function (samples) { //処理 } }
という形に変換されます。正直、JavaScript
のほうのメソッドを手で書くように言われたら、頭がついていきません。function
がたくさん出てきて読みづらいですし。
引数のsamples
は表示対象オブジェクトのリストですが、JavaScript
ではany
です。TypeScript
なら型情報を出しながら、しかも誤った要素を参照する危険性を減らしながら、安全にコーディングできます。
このおかげで、既存の知識を活用しながら、素早くコーディングできました。
躓いた点
TypeScript
は便利でしたが、躓いた点もあります。
thisの扱い
TypeScript
では、クラス内のプロパティをthis.プロパティ
みたいな形で参照できます。
ただ、クラス内でHTML要素のイベントを作成し、登録した際に、そのイベント内のthis
がクラスではないものが入ってきました。
ソース例はこんな感じです。(TypeScript)
constructor(combo1: HTMLSelectElement, combo2: HTMLSelectElement) { this.parentCombo = combo1; this.childCombo = combo2; this.index = this.parentCombo.selectedIndex; this.parentCombo.addEventListener("change", this.parentChanged); }
このthis.parentChanged
内がおかしくなっていました。
解決策として、イベントのメソッドをアロー式にして、プロパティとして宣言すればいいというのを見つけ、そしたらうまくいきました。下記のような感じです。
parentChanged = () => { //処理 }
正直よくわかりません。きっとJavaScript
をよく知る必要があるのでしょう。
いくら便利にコーディングできるとはいえ、JavaScript
を無視できるわけではない点は、肝に銘じたほうが良いと感じています。
おわりに
あくまで感想、という内容になります。
動的ページを作るハードルは、もっと高いと思っていましたが、上に書いた検索ページ自体はWeb API
の準備やルーティング等、バックエンドの作業含めて一日で作成できました*6。
TypeScript
は、取っつきやすい、という利点があるように思っています。JavaScript
のカオスさを軽減している感じです。
しかし、はまりポイントがあるようですし、JavaScript
自体の学習も必要だと思いました。
フロントエンドも楽しいです。すごく勉強になりました。