こんにちは。
TypeScript Advent Calendar 23日目の記事となります。
昨日22日目はmizchiさんでした。
今日は、まだTypeScriptを使っていない人、特に、「普段JavaScriptをよく触っていて、altJSに興味はあるけど、いまいち新しい言語を覚えるほどのモチベーションはない」という人に向けて、僕がTypeScriptを使いはじめて感じたことを書いてみたいと思います。
筆者がTypeScriptを使い始めるまでのプログラミング言語遍歴
話を始める前に、まずは筆者がこれまでに使ってきたプログラミング言語を振り返ってみます。
- JavaScript (2000〜現在)
- HSP (2001〜2003)
- PHP (2004〜2009)
- Python (2009〜現在)
…というように、まともに触ったことがあって、それなりに使えるようになったプログラミング言語は、どれも動的型付言語ばかりでした。
(ちなみに、Javaは専門学校の授業で勉強したときに何だか馴染めずに覚えられなくて結局単位を落として、そのときに苦手意識が植え付けられてしまったのか、今に至るまで覚えられてません…)
(基本情報技術者試験の午後の言語問題はJavaで受けて受かったんだけどね…)
そんなわけで、「静的型付けってなんか面倒臭そう」「プログラマは変数の中身がどんな型なのかを意識しておくべきだし、それでいいじゃん」という意識でずっとプログラミングをやっていました。
そんな僕が如何にしてTypeScriptに、静的型付けの世界に入り込んでいったか。
JavaScriptらしさを目指していた頃
話は2012年に遡ります。
仕事でも趣味でも日常的にJavaScriptを書いていたわけですが、どうしてもソースコードが散らかってしまって後からわかりにくくなることがあって、この頃から「JavaScriptをわかりやすく綺麗に書きたい」と意識し始めました。
2012年頃の、僕のaltJS(というかCoffeeScript)に対するイメージは
「実行エラーが出たときに、どこがエラーになったのかわかりにくくなってしまう」(CoffeeScriptがSourceMapに対応するのは2013年のこと)
「新しい文法の別言語をまた覚えるのは気が進まない」(それなりにJavaScript書けるんだからそれが無駄になりそうでヤダ)
といったものだったのであんまり使う気にはならず、それからしばらくはパーフェクトJavaScriptのような本を読んでJavaScriptのクソみたいなわかりにくい仕様に対する理解を深め、JavaScriptをJavaScriptらしい書き方で書くことを目指していました。
TypeScriptとの出会い
さて2014年に戻って。
「JavaScriptをJavaScriptらしい書き方で書く」ことに限界を感じていた僕は、改めてaltJSを使いはじめることを検討しました。
この頃にはCoffeeScriptもSourceMapに対応していたので、以前感じていた「どこがエラーかわかりにくい問題」は解消されており、あとは別言語を覚えるモチベーションだけでした。
それならばとCoffeeScriptを少し触ってみたのですが、個人的にはどうもしっくり来ない点があり、はっきりと「これからはこれを使おう」と思うまでには至りませんでした。
どうしようかとまた悩んでいたときにわかめさんがTypeScriptを推していたので、静的型付けであることに若干の不安(僕が今までちゃんと使ったことがないから不安という意味)を感じつつも少し試してみたところ、すぐに好きになって、今に至ります。
ずっと動的型付けの世界で生きてきた人でもTypeScriptで静的型付けの世界に入り込めた理由
型推論が賢いので、必ずしも型を書かなくて良い
動的型付言語では、変数を宣言するときに変数の型を明示的に宣言することはありません(変数に型はないのだから当然ですが)。
JavaScriptならvarキーワードを付けるだけですし、Pythonはそれすらなくいきなり初期値を代入するだけで変数の宣言になります。
// JavaScript var foo = 10; var baz = "hoge";
一方、静的型付言語、例えばJavaで変数を宣言する場合は、ちゃんとその変数がどんな型なのかを明示する必要があります。
// Java int foo = 10; //整数 String baz = "hoge"; //文字列
動的型付言語をずっと使ってきた身からすると、これがちょっと面倒くさいわけです。
なんで“var
”ひとつで済むはずのことを、中身によって変えなきゃいけないんだよ…、と。
しかし、TypeScriptには型推論があります。初期値の型をそのまま変数の型として採用してくれるので、わざわざ変数の型を書かずに、普通のJavaScriptと同じようにvarキーワードを書くだけで問題ありません。
// TypeScript var foo: number = 10; //ちゃんと数値型だと宣言する場合 var baz: string = "hoge"; //同じく文字列型と宣言 var hoge = 10; //初期値を代入しているので、いちいち型を書かなくても //自動的に数値型だと認識してくれる
一方、関数の仮引数にはちゃんと型注釈を入れる必要がありますが、JavaScriptやPythonを書いているときでもdocコメントで引数の型を明示していたりしたので、それと同じようなものだという感じで、これについてはわずらわしさは感じませんでした。
ダックタイピング(っぽいこと)ができる
ダックタイピングは、ざっくり言うと「オブジェクトの型が何であっても、こういう名前のメソッドorプロパティを持ってさえいればOK」という動的型付言語の特徴のひとつですが、
静的型付言語であるTypeScriptでも、動的型付言語であるJavaScriptのスーパーセットだからか、ちゃんとそれっぽいことが出来る手段が用意されています。
function len(obj: {length: number}){ return obj.length; } //配列はlengthプロパティを持っている len(['foo', 'bar']); // => 2 //文字列もlengthプロパティを持っている len('hoge'); // => 4 //数字はlengthプロパティを持っていない len(10); // => エラー
関数lenの仮引数objの型が{length: number}
となっています。
これは、「number型のlengthという名前のプロパティを持っていること」を示していて、この条件に合致してさえいれば、配列だろうと文字列だろうとこの関数の引数として渡すことができます。
これを使えば、関数中で呼び出したいメソッド・プロパティが必ず定義されていることを確認できる安全性と、引数で渡す変数の型が特定の型(とそのサブクラス)だけに制限されない柔軟性を兼ね備えたソースコードを書くことができます。
こういうやつのことを構造的部分型って呼ぶそうです。へー。
JavaScriptをそれなりに扱える人がTypeScriptを使うメリット
JavaScriptに近い感覚で書ける
他のaltJSがJavaScriptではない言語でJavaScriptを書き出すものが多いのに対し、TypeScriptはちょっと便利な機能と型に関する制約が増えたJavaScriptくらいのイメージです。
その「ちょっと便利な機能」も、将来のJavaScriptの仕様として考えられているものを先取りしただけのものがほとんどです。
例えばECMAScript6で採用されたアロー関数とか。
//普通に書いた場合 document.addEventListener("DOMContentLoaded", function(){ console.log("foo"); }, false); //アロー関数を使って書いた場合 document.addEventListener("DOMContentLoaded", () => { console.log("foo"); }, false);
TypeScriptだとアロー関数式で書いた場合はthis
が上書きされないなど、JavaScriptと挙動が異なる部分もありますが、アロー関数そのものの文法は同じです。
既にある程度JavaScript書けるよっていう人なら、今までのJavaScriptの知識を引き継げ、新しく覚えることも少なくて済みます。
しかもその新しく覚えることは将来のJavaScriptの仕様の先取りにもなるので、もしTypeScriptを使うのをやめたとしても知識がまったく無駄になることはないでしょう。
行儀の良いJavaScriptを書きやすくなる
一方の「制約」について。
今までも「(少し)きっちりしたJavaScript」になるように制約を加えたstrict mode("use strict"
)というのがありました。
このモードを使うと、例えばvarで変数を宣言するのを忘れて暗黙的にグローバル変数を作ってしまうとか、代入できない変数やキーワードに代入しようとしてしまうとかいった、バグの原因になりそうなことがエラーになります。
"use strict"; hoge = "aaa"; //varを使わずに変数を宣言してしまっているのでエラー eval = 19; //evalには代入できないのでエラー
TypeScriptを使うと、関数を呼び出すときの引数の型が間違っているなど、やはりバグの原因になりそうなことがエラーになります。
TypeScriptは型に関してのもう一つのstrict modeというふうにも考えられるでしょう。
そして、それらに慣れれば、素のJavaScriptを触ることになったとしても、同じように型を意識したコードを書けるようになることでしょう。(※効果には個人差があります)
個人的には、TypeScriptを使う時はstrict modeも同時に使用し、さらにコンパイルオプションで暗黙的なanyを許さない--noImplicitAny
を付けて、出来る限りきっちりとしたコードを書くようにしています。
いざとなったら生JavaScriptをメンテできる安心感
TypeScriptの最大の利点はめっちゃ綺麗なJavaScriptを吐き出すのでTypeScriptから逃げ出したくなったらいつでも逃げ出して変換後JSをメンテする体制に移行できることだよ!!! #tenka1altjs
— わかめ@TypeScriptカッコガチ (@vvakame) 2014, 6月 8
まさにこれです。
altJSの中には、より高速で動作するようにソースコードの最適化を自動的に行う反面、元々のコードとは全く別物のコードが出力されるものや、膨大な独自ランタイムが付与されるなどして人間には到底読めないようなJavaScriptを出力するものもあります。
TypeScriptはソースコードの最適化はせず、書かれたソースコードをそのままJavaScriptに変換していくだけで、また、ランタイムが出力されるのもクラスを使った場合の数行程度だけなので、変換前と変換後の対応がわかりやすく、人間にも読みやすいJavaScriptを出力してくれます。
TypeScriptを気に入って使い続けてもらえるのが一番いいことだとは思いますが、もしTypeScriptを使うのをやめることになったとしても、変換後のJavaScriptをそのままそれ以降の改修元として利用することができますので、後で発生する手戻りは少なく済むでしょう。
なお、変換後のJavaScriptの読みやすさで言うとCoffeeScriptもまぁまぁでしたが、Rubyの仕様に由来している「関数内で最後に評価された式の値が、勝手にその関数の戻り値になる(暗黙的にreturnされる)」という仕様が、僕はどうしても好きになれませんでした…。
TypeScriptは余計な事はせず、ただ逐一変換していくのみなのがシンプルで好みです。
というわけで、拙い文章ではありましたが、
TypeScriptは、JavaScriptをよく知らない・苦手な人よりも、既に知っている・得意な人にこそ向いていて、
動的型付の世界の住人にも優しく静的型付の世界に導いてくれるaltJSである、
…という魅力が少しでもお伝えできたのなら幸いです。
明日はらこらこさんがWebStormでTypeScript書くときに少しだけ幸せになれるTipsを書いてくれるみたいです。
僕も普段IDEはIntelliJ IDEAを利用しているので楽しみです。
[…] 「生JavaScriptで十分」な人にこそTypeScriptをおすすめしたい理由 […]