補足:2021年6月
結構昔に書いた記事ですが、今でもたまにアクセスがある(ありがとうございます)ようなので使命感に駆られて追記。
本編の冒頭にもあるように、これは2018年の記事です。なので色々と書いてますが、2021年の人間の立場からTypeScriptの導入について申すのであれば一言です。
使いましょう。
もはや「TypeScriptを使う理由」とか言ってる時代はとっくの昔に終わっています(Elmとかそういう、他の型付きAltを使いたいなら別ですが)。
もちろんstrict mode一択ですからね。
当時は採用云々とか書いてましたが、逆にいまTypeScript書けるかどうかってのはフロントエンドエンジニア採用の足切りラインとしてちょうどいいくらい(書けるってのが程度かにもよりますけど)だとおもいます。
好き嫌いはともかく、TypeScriptを使えないエンジニアを雇ってもフロントエンドの頭数に入れることはできません。
以上!
本編
こちらは株式会社LOBの2018年アドベンドカレンダーの内容としてお送りしてます。
前回はLOBのCTOによる 大規模プロジェクトの管理画面を育てるために TypeScript + React を選んだ理由 でした。
フロントエンドの技術選定に関わる話題、ということで僕からは「なんかいまTypeScriptめっちゃ流行ってるらしいけど導入して大丈夫なん?」みたいに迷っている人向けに考慮すべきことを書くことにしました。
楽 ≠ 簡単
まず僕個人の感想ですが、今後は何か特別な理由がない限りはフロントエンドをTypeScript以外で書くことはないとおもいます。
なぜならTypeScriptで書いた方が圧倒的に楽だからです。
しかし、「楽になる」のは「簡単になる」ことを意味しません。というよりむしろ、それぞれのスキルセットや好み次第では難しく、辛くなる可能性すらあるでしょう。
TypeScriptでフロントエンドを書くことの難しさ
Qiitaにある良記事に、 TypeScriptの型入門 という記事があります。
大変良くまとまっていてわかりやすいので、読んだことがない人は一度読んでおいてもらえると話が早いです。
1. TypeScriptは現状「別に使う必要はない」ツール
JavaScriptの知識は、どんなトランスパイラを使おうがフロントエンドをやる上では必ず求められる知識ですが、TypeScriptはそうではありません。あくまで更なる便利さを求めて使うツールです。
逆にいうならば、使いこなさなければ意味がないものなのです。
「静的型付け言語だとコンパイラが簡単なミスを発見してくれるので楽になる」というのは基本的に真なのですが、TypeScriptは「漸進的型付け」という考え方の元に作られているため、コンパイラがどれくらい仕事をしてくれるかは使い手のレベルによって変わってしまいます。
使用者のリテラシー次第では容易に「コードの量は1.5倍だけど信頼性は生のJavaScriptと変わらない……」という落とし穴にはまり込んでしまいます。
Javaのような言語でも「全てのメソッドの引数と返り値がObjectで定義されててワロタ」という地獄を見たことがある人がいる*1とおもうんですが、TypeScriptはもっと簡単に同じことができてしまいます*2。
上のような例であってもJavaを動かすにはJavaがJavaである必要があるので、つまり色々仕方ない。
しかしTypeScriptは結局JavaScriptとして動作させるので、有効活用しなければ存在意義がありません。
道具を使いこなすというのは実はなかなか高度な技能です。大抵の人は得意な言語であっても簡易的な機能だけを使い、公式のリファレンスすらほとんど読みません。
2. いきなり高めの型リテラシーを求められる
最初の型入門記事ですが、入門というのは内容が高度じゃねと思った方も多いんじゃないでしょうか。
しかし中身を知らずにコピペでコードを書き散らすならともかく、普通にコードを書く場合は少なくとも一通りちゃんと知識としてもっていなければなりません。
なぜなら未だに全てTypeScriptで書かれたライブラリというのは少ないため、JavaScriptの自由すぎる世界観と接続するためにTypeScriptの型機能が総動員されているケースが多いからです。
また今ではかなり充実してきてはいますが、それでも .d.ts
の存在していないライブラリもあります。そういった場合は自分でdeclareを書かねばなりません。
さらに .d.ts
の内容が間違っていたり考慮不足だったりすることなんかはまれによくあります。また、ライブラリとの接続部分でコンパイルエラーが出た場合、エラーメッセージが長すぎて見切れたりするので、原因が自分のコードなのかライブラリ側なのかを考えるためにコードを読む必要があります。
最低でも入門記事の内容は頭に入っていると、これらの事態が発生しても自己解決できるようになり心の平穏が得られます。
逆に何もわからないですぐにanyを書いてコンパイルエラーを解決していると突然現れたランライムエラーに刺されてお前は死ぬ。
noImplicitAnyの罠
implicit anyは難易度を上げる魔法の呪文。
ちなみに古い記事には「いきなりstrictでやっていくと辛いから noImplicitAny
はfalseにしておいたほうがいいよ」というものがあったりなかったりするかもしれないですが、それは古い情報です。現代ではそんなものは不要です。
ImplicitAnyはただただTypeScriptの難易度があがるだけで特に何も得るものがない罠機能です。Implicit anyを許容するとお前のアプリケーションの治安は死ぬ。tsconfig.jsonは strict: true
一択です。
型推論が効いているから型が省略されているのか、それともimplicit anyのせいで省略が許されているのか全部理解できる人間TypeScriptパーサーならimplicit anyを許容できるかもしれない。
万が一「implicit anyを許容しないと書けない」と感じている場合は、おそらくTypeScriptに期待するものが間違っているか静的型付け言語の知見が足りないとおもわれます。その状態で導入すると後々不幸になるとおもうので諦めて生のJavaScriptで書くという選択肢を取るのは悪いことじゃないとおもいます。
3. 初速が出ない
僕は今年の4月くらいから7〜8ヶ月くらいTypeScriptを書き続けていて、今では普通に書く分には生のJavaScriptと同じ程度の速度でコーディングできますが、やはり初速は落ちるようにおもいます。
使わなければならないライブラリがあればいちいち型定義が存在しているのか確認しなければならないですし、存在してなければだいたいを探すのか自分で定義するのか考えねばなりませんし、PRを送ってマージされてリリースされるのを待ったりする時間も発生します。
1ヶ月も書けばTypeScriptで書いた方が効率が上がる状態にはもっていけますが、その1ヶ月でプロトタイプを出すのが重要なこともあるでしょう。そういった状況にTypeScriptはおすすめできません。
4. 採用が難しい
正直なところ、高度な静的型付けをフロントエンドに求めてしまう人たちの勢力というのは未だにあまり大きくはありません。
今までフロントエンドをやってきた……という人たちは型への親和性が低いですし、逆にScalaなどをやってきた人たちでフロントエンド寄りという人は少ないとおもいます。
そういう意味で、ただでさえ少ない、GUI化した現代のフロントエンドに対応できるエンジニア……という要件に型リテラシーが入り込んでしまうのはかなりの厳しさがあります*3。
個人的な意見といたしまして、やっていき強めにキャッチアップしてたC#erやモバイルerなら一ヶ月そこらでつよつよフロントエンジニアに転向できるとおもうので、そういう方がいらっしゃいましたら僕に連絡してください。
まとめ
まとめです。
TypeScriptは
- 使いこなせば最高
- 使いこなせなければ存在自体が負債になりかねない
- 実務で使うハードルは高い
- 採用しんどい
- noImplicitAny: falseはマジでやめろstrictにいけ
です。
何か質問などありましたらご自由にどうぞ。
次はインフラ兄貴タカハシによる AnsibleのTemplate機能を使ってGCPを管理するTerraform設定を生成する です。
追記
文章構成の拙さからうまく考えが伝わっていないような気がしたのであとがき。
僕は新しくて*4便利そうなものは全部使って失敗しちまえというのが基本スタンスなので、上の記事が「失敗するからやめとけ」というように捉えられてしまったのであればごめんなさい。
ということで、僕の基本スタンスとしてはTypeScript大推奨です。最初にも書きましたが、もう全部これでいいよ的な思想に染まりつつあるくらいには気に入ってます。
次に「未経験者は使うな」なんてことは全く考えておりません。というか人間は生まれた瞬間には呼吸すら未経験なはずなので「やったことないからやらない」は不可能です。多少の火傷覚悟で新しい技術をぶっこめない現場なんて僕は退屈で死んでしまいます。どんどんやりましょう。
しかし色々な議論なんかを眺めていると、例えばリスト処理専用機能みたいに捉えられてしまいがちなGenericsは屁をこくよりも頻繁に出てきますし、便利なunion型ですが
とかく流れの速さについて色々と言われがちな現代のフロントエンドですが、正直ここ3年くらいは特に大きな知識のアップデートも必要なく落ち着いている現状です。……という意見がすでに世間の感覚と乖離しているという自覚なしでアジるのは、僕はちょっと無責任かなとおもいます。
環境構築に言及すると話がややこしくなるのでしませんでしたが、TypeScriptのコンパイルも僕はbabelでパースしながらtscで型チェックのみする体制でやってます。このやり方なら既存のJSをTSに書き換えていく場合でも簡単に混在できますし、babelがパース可能な状態であれば最悪型エラーが出てる状態でもリリース可能(そんなことするかどうかはともかく)です。
あとこの辺の環境はアップデートのたびに壊れがちなんですが、こまめにアップデートしないとdiffがでかくなりすぎて半年後のアップデートがしんどくなります。ライブラリの新バージョンが出たら型定義も更新しないといけませんし、そのときに定義が壊れる可能性もあります。
僕がペシミスティックな見方をしているだけなのかもしれないですが、90%の現場は人手も時間も不足している状態なんじゃないかとおもいます。正直なところ、専業フロントエンドエンジニアであってもbabelやwebpackの設定をゼロから自分でやれる人*5がどれくらいいるのか、ちょっと不安です*6。
TypeScript導入の手間、維持の苦労なんかの話はそのまんま木こりのジレンマみたいな話です。
人手が足りなくて、忙しい現場だからこそTypeScriptを入れるべき! これは正論です。しかし斧を研ぐのに手間がかかるのはそうですし、刃物の研ぎにはそれなりの技能が必要なのも事実です。
色々な人の色々な意見があるので結局は自己判断自己責任なんですが、こういう可能性もあるよということで参考程度にしていただけたらなとおもいます。
まだ導入を迷っている人はジョジョの5部を読んで覚悟について学びましょう。
こちらからは以上です。