TypeScriptを使っている風景をGIFアニメで説明します。TypeScript良いって聞くけど良くわからないのでスルーしてしまっているという方は多いのではないでしょうか? 使ってみてはじめて感じるものもありますが、文字で記事を見るだけではなかなか想像しづらいと思いますのでGIF動画でいくつか見られるようにしてみました。
今回はVSCode上でNext.jsのTypeScriptテンプレートを使って例をあげていきます。理由としてはプロジェクトを生成すればすぐ動かせるのと、ReactはJSXを使っていますが基本的には素の形式のためTypeScriptの恩恵を受けやすいためです。Vue.jsのvueファイルだとTypeScriptの恩恵を受けにくい場合が多いため、今回はそちらを選択しました。
せっかくですので実際にコードをいじりつつ見てみると面白いと思います。リポジトリは下記です。
next.js/examples/with-typescript at canary · zeit/next.js
下記でcloneし、
yarn create next-app --example with-typescript with-typescript-app
下記で実行です。
yarn dev
まず比較として、TypeScriptのような厳密な型の無い言語の場合に困ることをあげてみます。
例えばnameという氏名が入っているカラムを無理やり半角スペースで区切って姓と名を分けて表示したい、という場合、例としてPHPで書くと下記のようになります。(例のためあまりきれいな形ではないです)
まずは分割するメソッドを作成します。
public function splitName()
{
$parts = explode(' ', $this->name);
return ['sei' => $parts[0], 'mei' => $parts[1]];
}
こんな感じで、勝手に独自の配列や、Rubyとかでもハッシュを作成してreturnするパターンを作ることもあるのではないかと思います。そしてそれをコントローラでビューに渡したりします。
$this->set('seimei', $user->splitName());
そしてそれをテンプレート側で表示します。
<div>
姓:<?= $seimei['sei'] ?>
</div>
<div>
名:<?= $seimei['mei'] ?>
</div>
これで実装は可能です。でもこれですが、splitNameメソッドが「sei、meiはかっこ悪いからlastName、firstNameに変えて」となってしまった場合。テンプレート側では存在しないキーを指定する形になってしまうためエラーになってしまいます。上記のように1箇所だけ書いている場合は問題ないかもしれませんが、色々なページでいくつも書いていると抜けが出る恐れもあります。
これをTypeScriptで書いてみます。
function splitName(user: User) {
const parts = user.name.split(/ /)
return { sei: parts[0], mei: parts[1] }
}
そして実際に表示している箇所に追記します。
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>
)
処理の流れ的は先程のPHPと全く同じです。ただ、ここからがTypeScriptの便利なところです。
まず、適当に作ったsplitNameという関数ですが、暗黙で返り値の型が定義されるためカーソルを合わせるとこんな感じに固定された返り値の型が表示されます。
もちろん補完も効きますので入力ミスによる不具合も発生しません。もちろんjsx上で入力している場合もです。
Vue.jsの場合は独自のファイル形式のため、テンプレート上等では補完等は効いていないと思います。(2019/8現在)(なにか方法はあるのかもですが)
返り値を変えると型が変わり、表示している箇所が間違いになるのですぐにエラーになり気づくことが出来ます。
もちろんwatchしている場合はすぐにエラーになりビルドに失敗しますので決してこの原因で本番にて問題が発生することはありません。
とはいえ本来は自分でちゃんと定義してあげたほうが良いと思います。そもそも返り値を間違えてしまっていても気づくことができますし、型は別ファイルにしておけば別のファイルからも参照することが出来ます。
type SeiMei = {
lastName: string
firstName: string
}
function splitName(user: User): SeiMei {
const parts = user.name.split(/ /)
return { lastName: parts[0], firstName: parts[1] }
}
typeかinterfaceで同じような事ができるため、適宜使い分けてください。
例えばユーザーにステータスのようなものがあったとします。status
というカラムで、enumや文字列でステータスを定義している場合などです。例えば通常ユーザーであれば user.status = 'normal'
、停止中ユーザーであればuser.status = 'disabled
、上客であればuser.status = 'special'
など。
こういうものも一文字間違えるだけで不具合の原因になりますし、もしDBにそれを保存してしまうと様々な箇所で影響が出てとんでもないことになってしまいます。TypeScriptだとこういうものも型(文字リテラル型)にすることができます。
type UserStatus = 'normal' | 'disabled' | 'special'
interface User {
status: UserStatus
}
実際に操作するとこのようにエラーを出したり補完してくれたりします。
文字リテラル型ではなく列挙型(Enums)を使うこともできます。DBの型との関連によって適切なものを使い分けていきましょう。
Enums - TypeScript Deep Dive 日本語版
importも自動で行ってくれます。型の補完をする際に、importされていなければ自動的に追加してくれます。
自分で作った定義だけでなく、node_modules内のパッケージなども型情報があれば補完&importしてくれます。(これもVue.jsの場合はうまくいったりいかなかったりする場合があります)
TypeScriptは他にも便利な機能がたくさんありますが、とりあえず使ってみて最初に感じるであろう便利な部分だけをまとめてみました。
TwitterのTLを見ていると時々「TypeScript使い始めたら他の言語が怖い」という発言を見かけます。正直今は僕もPHPやRubyで配列やハッシュを書くのが怖いです。とはいえ全部classで書くのかと言うとそれも冗長すぎる気もしますしでもそうでなければテストを書かなきゃいけないですしなかなか悩ましいです。やはり言語自体で型を持ってくれているというのはありがたいし楽しいし楽です。
まあとはいえ全部TypeScriptにするわけにはいかないので今後もテストを書きつつやっていくのでしょう。その分TypeScriptを使って開発する時の楽しさが増すのだと思います。
ということで是非使ってみてください。コツとしては、自分で設定せず今回のように最初から設定済みの公式テンプレートのようなものを使ったりするのがおすすめです。既存のプロジェクトがあるから難しい、という場合も、そういったプロジェクトの設定を参考にすると良いと思います。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント