tag:crieit.net,2005:https://crieit.net/tags/VisualStudioCode/feed 「VisualStudioCode」の記事 - Crieit Crieitでタグ「VisualStudioCode」に投稿された最近の記事 2019-08-19T08:58:52+09:00 https://crieit.net/tags/VisualStudioCode/feed tag:crieit.net,2005:PublicArticle/15334 2019-08-19T08:27:39+09:00 2019-08-19T08:58:52+09:00 https://crieit.net/posts/TypeScript-GIF TypeScriptの開発をGIFアニメで見てみる <p>TypeScriptを使っている風景をGIFアニメで説明します。TypeScript良いって聞くけど良くわからないのでスルーしてしまっているという方は多いのではないでしょうか? 使ってみてはじめて感じるものもありますが、文字で記事を見るだけではなかなか想像しづらいと思いますのでGIF動画でいくつか見られるようにしてみました。</p> <p>今回はVSCode上でNext.jsのTypeScriptテンプレートを使って例をあげていきます。理由としてはプロジェクトを生成すればすぐ動かせるのと、ReactはJSXを使っていますが基本的には素の形式のためTypeScriptの恩恵を受けやすいためです。Vue.jsのvueファイルだとTypeScriptの恩恵を受けにくい場合が多いため、今回はそちらを選択しました。</p> <p>せっかくですので実際にコードをいじりつつ見てみると面白いと思います。リポジトリは下記です。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/zeit/next.js/tree/canary/examples/with-typescript">next.js/examples/with-typescript at canary · zeit/next.js</a></p> <p>下記でcloneし、</p> <pre><code class="sh">yarn create next-app --example with-typescript with-typescript-app </code></pre> <p>下記で実行です。</p> <pre><code class="sh">yarn dev </code></pre> <h2 id="厳密な型の無い言語で困ること"><a href="#%E5%8E%B3%E5%AF%86%E3%81%AA%E5%9E%8B%E3%81%AE%E7%84%A1%E3%81%84%E8%A8%80%E8%AA%9E%E3%81%A7%E5%9B%B0%E3%82%8B%E3%81%93%E3%81%A8">厳密な型の無い言語で困ること</a></h2> <p>まず比較として、TypeScriptのような厳密な型の無い言語の場合に困ることをあげてみます。</p> <p>例えばnameという氏名が入っているカラムを無理やり半角スペースで区切って姓と名を分けて表示したい、という場合、例としてPHPで書くと下記のようになります。(例のためあまりきれいな形ではないです)</p> <p>まずは分割するメソッドを作成します。</p> <pre><code class="php">public function splitName() { $parts = explode(' ', $this->name); return ['sei' => $parts[0], 'mei' => $parts[1]]; } </code></pre> <p>こんな感じで、勝手に独自の配列や、Rubyとかでもハッシュを作成してreturnするパターンを作ることもあるのではないかと思います。そしてそれをコントローラでビューに渡したりします。</p> <pre><code class="php">$this->set('seimei', $user->splitName()); </code></pre> <p>そしてそれをテンプレート側で表示します。</p> <pre><code class="php"><div> 姓:<?= $seimei['sei'] ?> </div> <div> 名:<?= $seimei['mei'] ?> </div> </code></pre> <p>これで実装は可能です。でもこれですが、splitNameメソッドが「sei、meiはかっこ悪いからlastName、firstNameに変えて」となってしまった場合。テンプレート側では存在しないキーを指定する形になってしまうためエラーになってしまいます。上記のように1箇所だけ書いている場合は問題ないかもしれませんが、色々なページでいくつも書いていると抜けが出る恐れもあります。</p> <h2 id="TypeScriptで書いてみる"><a href="#TypeScript%E3%81%A7%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B">TypeScriptで書いてみる</a></h2> <p>これをTypeScriptで書いてみます。</p> <pre><code class="typescript">function splitName(user: User) { const parts = user.name.split(/ /) return { sei: parts[0], mei: parts[1] } } </code></pre> <p>そして実際に表示している箇所に追記します。</p> <pre><code class="jsx"> const seimei = splitName(user) return ( <div> <h1>Detail for {user.name}</h1> <p>ID: {user.id}</p> <p>Last Name: {seimei.sei}</p> <p>First Name: {seimei.mei}</p> </div> ) </code></pre> <p>処理の流れ的は先程のPHPと全く同じです。ただ、ここからがTypeScriptの便利なところです。</p> <h2 id="勝手に型を定義してくれる"><a href="#%E5%8B%9D%E6%89%8B%E3%81%AB%E5%9E%8B%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%82%8B">勝手に型を定義してくれる</a></h2> <p>まず、適当に作ったsplitNameという関数ですが、暗黙で返り値の型が定義されるためカーソルを合わせるとこんな感じに固定された返り値の型が表示されます。</p> <p><a href="https://crieit.now.sh/upload_images/a0b376c790262ade844136c1d38142335d4ede4fbeacc.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a0b376c790262ade844136c1d38142335d4ede4fbeacc.gif?mw=700" alt="" /></a></p> <h2 id="補完も効く"><a href="#%E8%A3%9C%E5%AE%8C%E3%82%82%E5%8A%B9%E3%81%8F">補完も効く</a></h2> <p>もちろん補完も効きますので入力ミスによる不具合も発生しません。もちろんjsx上で入力している場合もです。</p> <p><a href="https://crieit.now.sh/upload_images/031bf31fe270d8f91da7adf2c35f8a8f5d4edf48e68f9.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/031bf31fe270d8f91da7adf2c35f8a8f5d4edf48e68f9.gif?mw=700" alt="" /></a></p> <p>Vue.jsの場合は独自のファイル形式のため、テンプレート上等では補完等は効いていないと思います。(2019/8現在)(なにか方法はあるのかもですが)</p> <h2 id="返り値を変えたら即エラーになる"><a href="#%E8%BF%94%E3%82%8A%E5%80%A4%E3%82%92%E5%A4%89%E3%81%88%E3%81%9F%E3%82%89%E5%8D%B3%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B">返り値を変えたら即エラーになる</a></h2> <p>返り値を変えると型が変わり、表示している箇所が間違いになるのですぐにエラーになり気づくことが出来ます。</p> <p><a href="https://crieit.now.sh/upload_images/dd01a8a4b251166921e2a12453917c5e5d4ee06692c58.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/dd01a8a4b251166921e2a12453917c5e5d4ee06692c58.gif?mw=700" alt="" /></a></p> <p>もちろんwatchしている場合はすぐにエラーになりビルドに失敗しますので決してこの原因で本番にて問題が発生することはありません。</p> <p><a href="https://crieit.now.sh/upload_images/8bc23d58c9f7d0f0de702cbe5bb687745d4ee1649db08.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8bc23d58c9f7d0f0de702cbe5bb687745d4ee1649db08.png?mw=700" alt="" /></a></p> <h2 id="自分で型を定義したほうが親切"><a href="#%E8%87%AA%E5%88%86%E3%81%A7%E5%9E%8B%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%97%E3%81%9F%E3%81%BB%E3%81%86%E3%81%8C%E8%A6%AA%E5%88%87">自分で型を定義したほうが親切</a></h2> <p>とはいえ本来は自分でちゃんと定義してあげたほうが良いと思います。そもそも返り値を間違えてしまっていても気づくことができますし、型は別ファイルにしておけば別のファイルからも参照することが出来ます。</p> <pre><code class="typescript">type SeiMei = { lastName: string firstName: string } function splitName(user: User): SeiMei { const parts = user.name.split(/ /) return { lastName: parts[0], firstName: parts[1] } } </code></pre> <p>typeかinterfaceで同じような事ができるため、適宜使い分けてください。</p> <h2 id="オリジナルの型も作れる"><a href="#%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%81%AE%E5%9E%8B%E3%82%82%E4%BD%9C%E3%82%8C%E3%82%8B">オリジナルの型も作れる</a></h2> <p>例えばユーザーにステータスのようなものがあったとします。<code>status</code>というカラムで、enumや文字列でステータスを定義している場合などです。例えば通常ユーザーであれば <code>user.status = 'normal'</code>、停止中ユーザーであれば<code>user.status = 'disabled</code>、上客であれば<code>user.status = 'special'</code>など。</p> <p>こういうものも一文字間違えるだけで不具合の原因になりますし、もしDBにそれを保存してしまうと様々な箇所で影響が出てとんでもないことになってしまいます。TypeScriptだとこういうものも型(文字リテラル型)にすることができます。</p> <pre><code class="typescript"><br />type UserStatus = 'normal' | 'disabled' | 'special' interface User { status: UserStatus } </code></pre> <p>実際に操作するとこのようにエラーを出したり補完してくれたりします。</p> <p><a href="https://crieit.now.sh/upload_images/b9d54e11dd10c51967b47e873842e9c45d502adb146f0.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b9d54e11dd10c51967b47e873842e9c45d502adb146f0.gif?mw=700" alt="" /></a></p> <p>文字リテラル型ではなく列挙型(Enums)を使うこともできます。DBの型との関連によって適切なものを使い分けていきましょう。</p> <p><a target="_blank" rel="nofollow noopener" href="https://typescript-jp.gitbook.io/deep-dive/type-system/enums">Enums - TypeScript Deep Dive 日本語版</a></p> <h2 id="自動でimportしてくれる"><a href="#%E8%87%AA%E5%8B%95%E3%81%A7import%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%82%8B">自動でimportしてくれる</a></h2> <p>importも自動で行ってくれます。型の補完をする際に、importされていなければ自動的に追加してくれます。</p> <p><a href="https://crieit.now.sh/upload_images/9bb28439e70f6d0c07d95b4843348d4e5d502ce2dd8ae.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9bb28439e70f6d0c07d95b4843348d4e5d502ce2dd8ae.gif?mw=700" alt="" /></a></p> <p>自分で作った定義だけでなく、node_modules内のパッケージなども型情報があれば補完&importしてくれます。(これもVue.jsの場合はうまくいったりいかなかったりする場合があります)</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>TypeScriptは他にも便利な機能がたくさんありますが、とりあえず使ってみて最初に感じるであろう便利な部分だけをまとめてみました。</p> <p>TwitterのTLを見ていると時々「TypeScript使い始めたら他の言語が怖い」という発言を見かけます。正直今は僕もPHPやRubyで配列やハッシュを書くのが怖いです。とはいえ全部classで書くのかと言うとそれも冗長すぎる気もしますしでもそうでなければテストを書かなきゃいけないですしなかなか悩ましいです。やはり言語自体で型を持ってくれているというのはありがたいし楽しいし楽です。</p> <p>まあとはいえ全部TypeScriptにするわけにはいかないので今後もテストを書きつつやっていくのでしょう。その分TypeScriptを使って開発する時の楽しさが増すのだと思います。</p> <h3 id="オススメの始め方"><a href="#%E3%82%AA%E3%82%B9%E3%82%B9%E3%83%A1%E3%81%AE%E5%A7%8B%E3%82%81%E6%96%B9">オススメの始め方</a></h3> <p>ということで是非使ってみてください。コツとしては、自分で設定せず今回のように最初から設定済みの公式テンプレートのようなものを使ったりするのがおすすめです。既存のプロジェクトがあるから難しい、という場合も、そういったプロジェクトの設定を参考にすると良いと思います。</p> だら@Crieit開発者