TypeScript/JavaScript ができるってつまり何ができるの?
「xxx ができる」というアピールに対して実際にどれぐらいできるのか?を見る場合、xxx の塊のまま “できる/できない” を二者択一することはないと思う。 レベル感にはグラデーションがあるはずで、そのグラデーションは 「xxx ができる」の内側の”複数の期待値” によって作られるはず。
“複数の期待値” とは以下のようなもの:
xxx ができるってことは、yyy の理解が深かったり、zzz の経験があったりするのかな?
私の場合、第一言語である「TypeScript (または JavaScript) ができる」というアピールからは離れられない (自分が言うことも、他人に言われることもある)。 「TypeScript/JavaScript ができる」とは具体的に「なにができる」ということなのかを理解するために、TypeScript/JavaScript の定義を確認して、“複数の期待値” を整理してみようと思う。
TypeScript ってなに?
公式ドキュメント (https://www.typescriptlang.org/) から引用しながら、TypeScript の定義を確認する。
構文
TypeScript is a language that is a superset of JavaScript: JS syntax is therefore legal TS.
ref: TypeScript for the New Programmer > A Typed Superset of JavaScript
- TypeScript は JavaScript のスーパーセットの言語
- JavaScript の構文は TypeScript の構文としても有効
「TypeScript は JavaScript の superset (上位集合) 」は以下のような図で表現できる。
「JavaScript (プログラミング言語) が TypeScript (プログラミング言語) に内包されている」とは「JavaScript の構文は TypeScript の構文としても有効」と言い換えられる。 以下のコードを例に考える。
const obj = { width: 10, height: 15 };
console.log(obj.width * obj.height); // 150
このコードはJavaScript の構文として正しいため、JavaScript として実行することができる。 JavaScript の構文として正しいコードは TypeScript の構文としても正しいため、このコードは JavaScript へ変換することができる1。
型
TypeScript is JavaScript with syntax for types.
- TypeScript はJavaScript に型の構文を追加したもの
前述の図の内、青色の範囲 (TypeScript から JavaScript を引いたset difference (差集合)) が型構文に相当する。 つまり、TypeScript と JavaScript の違いは型構文の有無と言える。
TypeScript is a typed superset, meaning that it adds rules about how different kinds of values can be used.
ref: types
- TypeScript は型付きの superset で、さまざまな種類の値の使用方法に関するルールを追加している。
型構文とは「値の使用方法に関するルール」のこと2。 TypeScript は「JavaScript で記述した値の使い方を型で表現できる」言語と言える。
ただし TypeScript は JavaScript の superset のため、前述のような型を書いていない「ただの JavaScript のコード」でもよい。 以下のコードを例に考える。
const obj = { width: 10, height: 15 };
console.log(obj.width * obj.takasa); // NaN
obj
オブジェクトは height
プロパティを持っているが、2行目の乗算で takasa
プロパティを参照している。
このコードを JavaScript として実行すると NaN
が出力される。
システムの仕様にもよるがおそらく NaN
は期待値ではない。しかし JavaScript の構文としては正しいため、実行して計算結果を得ることができる。
一方、TypeScript は実行前 (JavaScript への変換時) に型エラーがある(値を誤った方法で使用している)ことを報告してくれる。 上述のコードは型を全く書いていないが、TypeScript のコンパイラーは 型推論 によって型の情報を手に入れられる。
型システム
TypeScript offers all of JavaScript’s features, and an additional layer on top of these: TypeScript’s type system.
- TypeScript は JavaScript のすべての機能を提供し、さらにその上に TypeScript の型システムというレイヤーを追加する
JavaScript に追加するものの表現がバラついてて非常にややこしい3が、型推論のことも考慮すると、以下のような図の方が正確かもしれない。
「TypeScript ができます」の意味
ここまでの情報をまとめると、「TypeScript ができます」に対する “複数の期待値” は以下のように表現できる:
- TypeScript ができます
- JavaScript ができます
- TypeScript の型システムが分かります
JavaScript ってなに?
JavaScript (JS) は軽量でインタープリター型(あるいは実行時コンパイルされる)第一級関数を備えたプログラミング言語です。
ref: mdn > JavaScript
ソースコードをどのように解釈して実行するかは実行環境(JavaScriptエンジン)が決めることなので、プログラミング言語の説明文としてはちょっと変な気がする。 ちなみに V8 は インタープリター・ JIT コンパイラー両方を内蔵している。
JavaScript が第一級関数を備えているということは、superset である TypeScript も同様に第一級関数を備えている(関数がその他の変数と同様に扱われる)。
JavaScript はプロトタイプベースで、マルチパラダイムで、シングルスレッドで、動的な言語であり、オブジェクト指向、命令型、宣言型(関数プログラミングなど)といったスタイルに対応しています。
ref: mdn > JavaScript
JavaScript は動的型付け言語のため、実行時に変数にデータ型を割り当てる。 一方 TypeScript は静的型付け言語のため、実行前にデータ型を判定する。
実行環境
多くのブラウザー以外の環境、例えば Node.js や Apache CouchDB や Adobe Acrobat などでも使用されています。
ref: mdn > JavaScript
JavaScript を実行できる環境は様々なので、厳密にはどの環境の「JavaScriptができる」と言っているかで話が変わるはず。 …とは言っても、2024年時点では実質 Web ブラウザーと Node.js の 2 択だと思うし、Chromium ベースのブラウザも Node.js も同じ JavaScript エンジン (V8) を使っているので、 言語・実行環境そのものに対する課題を解決する採用でもない限りここの差に注目する必要もない4。
構成要素
ウェブブラウザーの文脈で解釈されるこの「JavaScript」という包括的用語は、まったく異なる複数の要素を含んでいます。その要素とは、中核となるプログラミング言語(ECMAScript)、もう一つは DOM(Document Object Model)を含んだ Web API 群です。
「JavaScript」という用語の意味は実は少し広い。 JavaScript (意味が広い) のうち純粋なプログラミング言語の部分は ECMAScript という名前の言語に相当する。 「Web ブラウザーにおける JavaScript」はこの ECMAScript に加えて、Web ブラウザーが提供する様々な機能を呼び出すための API 群を含んだ概念を指している。
(Web ブラウザーにおける JavaScript) = (コア言語 (ECMAScript)) + (Web API)
It is best known as the language embedded in web browsers but has also been widely adopted for server and embedded applications.
ECMAScript はホスト環境に限定されないコア言語5として標準化されている。 この標準に従ったプログラミング言語の組み込み先として一番有名なのが Web ブラウザーなだけであって、Web ブラウザー以外でも、例えば Node.js でも ECMAScript が組み込まれている。
in the browser, we don’t have all the nice APIs that Node.js provides through its modules, like the filesystem access functionality.
ホスト環境が異なれば、JavaScript (意味が広い) のうち ECMAScript 以外の部分が異なる。Node.js であれば、Node.js が提供する API 群が「Node.js における JavaScript」の一要素になる。
(Node.js における JavaScript) = (コア言語 (ECMAScript)) + (Node.js API)
「JavaScript ができます」の意味
ここまでの情報をまとめると、「JavaScript ができます」に対する “複数の期待値” は以下のように表現できる:
- JavaScript ができます
- コア言語 (ECMAScript) が分かります
- 実行環境が提供する API 群が分かります
- Web ブラウザーの場合、 Web API 群が分かります
- Node.js の場合、Node.js が提供する API 群が分かります
- その他の環境
「TypeScript/JavaScript ができます」の意味 (まとめ)
粒度1 | 粒度2 | 粒度3 | 粒度4 |
---|---|---|---|
TypeScript ができます | JavaScript ができます | コア言語 (ECMAScript) が分かります | |
├ | Web ブラウザーの場合、 Web API 群が分かります | DOM | |
│ | ├ | Fetch API | |
│ | └ | 略、要素が多すぎる | |
└ | Node.js の場合、Node.js が提供する API 群が分かります | File system | |
├ | Modules: ECMAScript modules | ||
└ | 略、要素が多すぎる | ||
TypeScript の型システムが分かります | Static type-checking | ||
├ | Non-exception Failures | ||
└ | 略、要素が多すぎる |
ドキュメントに書いてある定義ベースで分解したので、この表はもともとの目的 (期待する要素を分解してレベル感を把握する) に対して大げさすぎたり、要素が不足している。 例えば、Web アプリケーションの開発者として ECMAScript (プログラミング言語の仕様) を隅々まで理解している必要は必ずしもなく(あってもいいけど)、MDN のチュートリアルやリファレンスを参考に期待値を決めてよいと思う。 逆に現行の仕様だけでなく提案(tc39/proposals)に関心があれば、それも十分レベル感の把握の参考になるはず。
Footnotes
-
正確には「エラーを発生させずに TypeScript として JavaScript へ変換することができる」。なぜなら、TypeScript のコンパイラーは不正な構文のコードでも JavaScript を出力する。 ↩
-
実行環境のみに注目しているから注目するほどの差がないだけであって、後述の API を考慮したりすると差はめっちゃある。そして、そもそも解決する課題が全然違う。 ↩