本ドキュメントは、まだ未完成ですが、ウェブフロントエンドの開発を学ぶときに、JavaScriptを経由せずに、最初からTypeScriptで学んでいくコンテンツとして作成されはじめました。TypeScriptは基本的にJavaScriptの上位互換であり、JavaScriptには歴史的経緯で古い書き方も数多くあります。そのため、文法を学ぶだけではなくよりモダンな書き方をきちんと学べることを目指しています。
現在、B2B企業であっても、B2C企業であっても、どこの企業もウェブのフロントエンドの求人が足りないという話をしています。
以前は、企業システムのフロントエンドというと、一覧のテーブルがあって、各行のCRUD(Create: 作成、Read: 読み込み、Update: 更新、Delete: 削除)の操作を作る、といったようにハンコを押すように量産するものでした。また、画面はテンプレートを使ってサーバーで作成して返すものでした。
しかし、ユーザーがプライベートで触れるウェブの体験というものもリッチになり、それに呼応するようにフロントエンドのフレームワークやら開発技術も複雑化しました。よりリアルタイムに近い応答を返す、画面の切り替えを高速にする、動的に変化する画面で効率よく情報を提供する、といったことが普通に行われるようになりました。
コンシューマー向けのリッチなウェブになれたユーザーが、1日の大半を過ごす仕事で触れるシステムが時代遅れなUIというのは良いものではありません。UIに関するコモンセンスから外れれば外れるほど、ユーザーの期待から外れれば外れるほど、「使いにくい」システムとなり、ストレスを与えてしまいます。
近年、React、Vue.js、Angularといった最新のフレームワークの導入は、企業システムであっても現在は積極的に行われるようになってきています。しかし、フロントエンド側での実装の手間暇が多くかかりますし、BootstrapとjQuery時代のように、ボタンを押した処理だけ書く、というのと比べると分量がかなり増えます。分量が増える分、モジュール分割の仕方を工夫したり、きちんと階層に分離したアーキテクチャを採用したり、きちんとした設計が求められるようになります。
フューチャーアーキテクトおよびフューチャーでは開発の方法論を定めて効率よく開発を行うことを実現してきており、典型的なサーバー側で処理を多く行うアプリケーションの場合は数多くの成功を納めてきています。一方で、前述のようにフロントエンド側の比重が高まると、当然のことながらプロジェクトに占めるフロントエンドの開発者の割合を高める必要があります。フューチャーではコンピューターを専門で学んできた学生以外にも多様な学生を受け入れて研修を行なっています。新卒教育の時間は限られているため、あまり多くのことを学んでもらうのは困難です。現在はサーバー側の知識を中心に学んでいます。
サーバーサイドJavaやSQLなどはほぼすべての社員が身につけていますが、フロントエンド側の開発を行なってもらうには新たな学習の機会の提供が必要です。趣味の時間で勝手に勉強しておいてね、というのは企業活動の中では認められません(趣味でやることを止めるものではありません)。業務遂行のために必要なリソース、知識は業務時間中に得られる体制を整えなければなりません。これまでは、お客様のニーズ的に高度なフロントエンドが必要な案件では、一部の趣味でやっていたメンバーやら、キャリア入社のメンバー、あるいは現場でそれぞれ独自に学んだりといったゲリラ戦で戦ってきましたが、お客様の期待にもっと答えられる体制を築くには、きちんと学べるコンテンツや教育体制の構築が必要ということが、フューチャーの技術リーダー陣の共通見解となっています。
フロントエンド開発の難しい点は、コードを書くのよりも環境構築の難易度が高く、また、その環境構築を行わないとコードが書き始められないという点にあります。また、JavaScript向けのパッケージでTypeScript用に型情報をコンパイラに教えてくれる定義ファイルが提供されていないと、開発時にそれも整備しなければなりません。しかし、これも初心者がいきなり手を出すのは厳しいものがあります。近年、コードジェネレータなどが整備されてきているため、 Vue.js
や React
、 Angular
といった人気のフレームワークと一緒に利用するのはさほど難しくなくなってきていますが、その部分はチームでシニアなメンバーが行うものとして、まずは書き方にフォーカスし、次に型定義ファイル作成、最後に環境構築というステップで説明を行い、必要な場所をつまみ食いしてもらえるようにすることを目指しています。
フロントエンドの開発がリッチになってきていると同時に、開発におけるムーブメントもあります。それはブラウザで動作するJavaScriptを直接書かなくなっているということです。 JavaScriptは2015年より前は保守的なアップデートがおこなわれていました。Netscape社(現Mozilla)が開発し、企業間のコンソーシアムで当初仕様が策定されていました。クラスを導入するという大規模アップデートを一度は目指したものの(ECMAScript 4)、その時は頓挫しました。しかし、ECMAScript 2015時点で大幅なアップデートが加えられ、よりオープンなコミュニティ、TC39で議論されるようになりました。
しかし、ブラウザの組み込み言語である以上、サーバーアプリケーションのJavaやPythonのようにランタイムをアプリケーションに合わせて維持したり更新するといったことはできません。そのため、高度な文法を備える言語でコードを書き、トラディショナルなJavaScriptに変換するというアプローチが好まれるようになりました。CoffeeScriptなどが一時広く使われたものの、現在よく利用されているのはBabelとTypeScriptです。
Babel(旧名6to5)はオープンソースで開発されている処理系で、ECMAScriptの最新の文法を解釈し、古いJavaScript環境でも動作するように変換します。プラグインを使うことで、まだ規格に正式に取り入れられていない実験的な文法を有効にすることもできます。実際、言語の仕様策定の場でも参考実装として活発に使われています。TypeScriptはMicrosoft社が開発した言語で、ECMAScriptを土台にして、型情報を付与できるようにしたものです。一部例外はありますが、TypeScriptのコードから型情報を外すとほぼそのままJavaScriptになります。言語仕様の策定においても、参考実装の1つとして扱われています。
大規模になってくると、型があるとコーディングが楽になります。型を書く文の手間は多少増えますが、昔の静的型付き言語と異なり、TypeScriptは「明示的に型がわかる場面」では型を省略して書くことができます。また、動的なオブジェクトなど、JavaScriptでよく登場する型もうまく扱えるように設計されています。そのような使い勝手の良さもあり、現在は採用数が伸びています。有名なOSSも実装をTypeScriptに置き換えたり、企業でも積極的な活用が進んでいます。
Babelにも、プラグインを追加して型情報を追加できるflowtypeというFacebook製の拡張文法がありますが、ライブラリに型情報をつけるのは、手作業で整備していかなければならず、シェアが高いほど型情報が手に入りやすく、開発の準備のために型定義ファイルを作る時間を別途かけなくて済みます。現時点で型定義ファイルの充実度が高いのはTypeScriptです。
まとめると
- 新しい記法を使うが、ブラウザの互換性を維持するコードを書く手法としてコンパイラを使うのが当たり前になってきた
- 大規模になると(小規模でも)、型情報があるとエラーチェックが実装中に行われるので開発がしやすくなる
- 型を持ったJavaScriptにはTypeScriptとflowtypeの2つがあるが、シェアが高いのがTypeScript
です。
「型情報を省くとほぼJavaScript」なのに、なぜわざわざ別のツールを導入してまでTypeScriptを使うのでしょうか?
型情報が得られることで開発が加速される、というので十分に元はとれます。また、最初からTypeScriptを書くメリットとしては、JavaScriptのライブラリをコンパイルして作る際に、型定義ファイルも同時生成できて、無駄がない点にあります。最初から書くことでTypeScript資産がたまり、さらにTypeScriptの開発が楽になります。
また、JavaScriptは極めて柔軟な言語です。関数の引数の型もどんなものでも受け付けるとか、引数によって内部の動作が大きく切り替わるようなコード(メソッド・オーバーロード)も書こうと思えば書けます。またTypeScriptの機能を駆使して、そのような関数に型情報を付与することもできます。しかし、TypeScriptで最初から書けば、そのような型付けに苦労するような、トリッキーな書き方がしにくくなります。結果として型定義のメンテナンスに時間を取られることが減ります。
それ以外にも、型情報が分かった上で変換を行うため、ループ構文など、いくつかのコードを変換するときに、Babelよりも実行効率の良いJavaScriptコードを生成することもわかっています。
本ドキュメントでは、大規模化するフロントエンド開発の難易度を下げ、バグが入り込みにくくなるTypeScriptを使いこなせるように、文法や環境構築などを紹介していきます。
最近ではJavaScriptの仕様はコミュニティで議論されています。TC39というECMA内部のTechnical Committeeがそれにあたります。 クラスなどの大幅な機能追加が行われたES6は、正式リリース時にECMAScript 2015という正式名称になり、それ以降は年次でバージョンアップを行なっています。
議論の結果や現在上がっている提案はすべてGitHub上で見ることができます。
機能単位で提案が行われます。 最初はstage 0から始まり、stage 1、stage 2とステップがあがっていきます。最初はアイディアでも、徐々にきちんとした仕様やデモ、参考実装など動くようにすることが求められていきます。stage 1が提案、stage 2がドラフト、stage 3がリリース候補、stage 4がECMAScript標準への組み込みになります。 1月ぐらいにstage 4へ格上げになる機能が決定され、6月に新しいバージョンがリリースされます。
TypeScriptも基本的には型がついたECMAScriptとして、ECMAScriptの機能は積極的に取り込んでいます。また、いくつかstage 2やstage 3の機能も取り込まれていたりします。
本ドキュメントはTypeScriptファーストで説明していきますが、JavaScriptとの差異があるところは適宜補足します。
ECMAScriptの仕様および、MDN、TypeScriptの仕様などは一番のリファレンスとしています。
- ECMAScript規格: https://www.ecma-international.org/publications/standards/Ecma-262.htm
- MDN: https://developer.mozilla.org/ja/docs/Glossary/JavaScript
- 本家サイト: http://www.typescriptlang.org/
下記のサイトは最近まではCompiler Internalなどが書いてあるサイトとしてしか思っていなくて、詳しくは見ていませんでしたが、現在ではかなり充実してきています。現時点では参考にはしてませんでしたが、今後は参考にする可能性があります。
- TypeScript Deep Dive: https://basarat.gitbooks.io/typescript/
- TypeScript Deep Dive日本語版: https://typescript-jp.gitbook.io/deep-dive/
本書のベースとなっているのは、本原稿を執筆した渋川がQiitaに書いたエントリーの イマドキのJavaScriptの書き方2018 [1] と、それを元にして書いた Software Design 2019年3月号 のJavaScript特集です。それ以外に、状況別のTypeScriptの環境構築について書いた 2019年版: 脱Babel!フロント/JS開発をTypeScriptに移行するための環境整備マニュアル [2] も内包していますし、他のエントリーも細々と引用しています。
これらの執筆においてもそうですが、本書自体の執筆でも、ウェブ上で多くの議論をしてくれた人たちとの交流によって得られた知識ふんだんに盛り込まれていますので、ここに感謝申し上げたいと思います。
[1] | https://qiita.com/shibukawa/items/19ab5c381bbb2e09d0d9 |
[2] | https://qiita.com/shibukawa/items/0a1aaf689d5183c6e0f1 |
本ドキュメントは クリエイティブ・コモンズ4.0の表示 - 継承 (CC BY-SA 4.0) [3] の元で公開します。修正や足したいコンテンツはPull Requestを出していただけるとうれしいのですが、改変の制約はありませんのでフォークしていただくことも可能です。また、商用利用の制限もありません。
著作権者名は「フューチャー株式会社(Future Corporation)」でお願いします。
なお、LICENSEファイルは Creative Commons Markdown から引用させていただきました。
[3] | http://creativecommons.org/licenses/by-sa/4.0/deed.ja |
本書はTypeScriptのエコシステムまで含めたすべてを説明しようとするものではありません。
例えば、既存のJavaScriptのライブラリのための型定義ファイルを作成する方法については紹介しません。時間が経てば有名ライブラリについてはほぼ網羅されることを期待していますし、自作していくときはゼロからTypeScriptでいけば、型定義ファイルは自動生成されるので不要です。
また、ジェネリクスや型システムの複雑な機能には深入りはしません。TypeScriptも、少しずつ着実にバージョンアップを重ねています。一般的に開発者がよく利用するようなケースにおいては、すでに書きやすくなるようにデザインされています。また、今現在は簡単に定義できないようなものがあったとしても将来バージョンで改善されて簡単に書けるようになると期待されるからです。
インターネット上ですべてのユーザーが見られるサイトを作る場合、現在の機能的な下限はInternet Explorer 11 [4] です。
Googleの検索エンジンのボットもこれとほぼ同等機能(const
、 let
ありのクラスなし)のChrome 41で固定されています [5] 。
それ以外には、バージョンアップがもう提供されていないiOSやAndroidのスマートフォンの場合に最新の機能が使えないことがあります。
ブラウザ以外ではGoogle Apps ScriptがECMAScript3にしか対応していません。
100%のブラウザとの互換性を維持するのは開発リソースがいくらあっても足りないため、捻出できる工数と相談しながら、サポート範囲を決めます。 ブラウザのバージョンごとにどの機能が対応しているかはECMAScript Compatibility Table[6]のサイトで調べられます。
新しいブラウザのみに限定できるイントラネットのサービスや、Node.js以外は、Babelなり、TypeScriptなりのコンパイラを使い、変換後の出力として古いブラウザ向けのJavaScriptコードに変換して出力するのが現在では一般的です。Lambda、Cloud Functions、Google App Engineなどは、場合によっては少し古いバージョンのNode.jsを対象にしなければならないため、これも変換が必要になるかもしれません [7] 。
TypeScriptの場合はほぼ最新のECMAScriptの文法に型をつけて記述できますが、コンパイル時に出力するコードのバージョンを決めることができます。 デフォルトではES3ですが、ES5、ES2015からES2018、ESNEXTとあわせて、合計7通りの選択肢が取れます。一部の記述はターゲットが古い場合にはオプションが必要になることもあります。最低限、ES5であれば、新旧問わずどのブラウザでも問題になることはないでしょう。
ただし、TypeScriptが面倒を見てくれるのは文法の部分だけです。たとえば、 Map
や Set
といったクラスはES5にはありませんし、イテレータを伴う Array
のメソッドもありません。
TypeScriptには tsconfig.json
というコンパイラの動作を決定する定義ファイルがあります。ブラウザの可搬性を維持しつつ、これらの新しい要素を使いたい場合には別途そこをサポートするものを入れる必要があります。現在、その足りないクラスやメソッドを追加するもの(Polyfillと呼ばれる)で、一番利用されるのが core-js
[8] で、Babelからも使われているようです。
出力ターゲットを古くすると、利用できるクラスなども一緒に古くなってしまうため、対策が必要です、まずは、ES2017やES2018などのバージョンのうち、必要なクラスを定義しているバージョンがどれかを探してきます。どのバージョンがどの機能をサポートしているかは、前述の compat-table が参考になります。
ターゲットに es5
を選ぶと、 lib
には ["DOM", "ScriptHost", "ES5"]
が定義されます。 lib
は使えるクラスとかメソッド、その時の型などが定義されているもので、これを増やしたからといってできることが増えたりはしませんが、「これはないよ」というコンパイラがエラーを出力するための情報源として使われます。この "ES5"
には、そのバージョンで利用できるクラスとメソッドしかないため、次のように ES2017
に置き換えます。
{
"compilerOptions": {
"target": "es5",
"lib": ["DOM", "ScriptHost", "ES2017"]
}
}
こうすると、 Map
などを使ってもTypeScriptのエラーにはならなくなりますが、変換されるソースコードには Map
が最初からあるものとして出力されてしまいます。
あとは、その Map
を利用している場所に、 import
を追加すると、その機能がない環境でも動作するようになります。
core-jsのオプションが知りたい場合は、core-jsのサイトのREADMEに詳しく書かれています。
import "core-js/es6/map";
[4] | Microsoft社がEdgeがChromiumベースにすることが発表され、現在ベータ版が配布されています。これまでのEdgeと異なり、Windows 7以降のすべてのWindowsで提供されるようになります。IEモードも搭載されてIEとのリプレースも行えるようになるため、IE基準で考える必要はなくなっていく予定です。 |
[5] | Google I/O 2019で、これが現時点の最新版と同じChrome 74に更新されることが発表されています。 |
[6] | http://kangax.github.io/compat-table/es6/ |
[7] | Lambdaは長らくNode.js 6というかなり古いバージョンを使っていましたが10が提供されて6はサポート終了になり、Node.js 6ベースのタスクの新規作成と更新ができなくなりました。 |
[8] | https://www.npmjs.com/package/core-js |