━目次━
以前こちらのイベントでTypeScriptのハンズオンをしました!
https://no-mount.connpass.com/event/159948/
「入門編」としてやったのですが「応用編」も次回のイベントでやるということで、上記のイベントに来れてない人やこれからTypeScriptを勉強したい!って人向けにブログにも残しておこうかなということで書いてます。
問題形式で解いていくことによって、TypeScriptの特性に触れたり、メリットを感じることができるかと思います。
今やフロントエンド開発でTypeScriptを使わない理由はないと言っても過言ではないので、Webに生きる人はある程度使えるようになっておきましょう( ̄^ ̄)b
それではいってみよ〜
TypeScriptとは
そもそもTypeScriptは何なんだっていう話ですが、もう既にネット上に色々説明があり今更書く必要もないので以下のページを参照してください。
まぁ簡潔に言えば、
JavaScriptに「型」という概念を組みこもう!
開発者間で認識を合わせやすい!
そうすれば色々バグを未然に防げる!
エディタでコード補完も効くから開発効率もUP!
みたいな感じです。ん〜素敵。
ハンズオン用のコード(CodeSandbox)
ではいよいよハンズオンにうつっていきましょう。
環境構築からやってたら皆さんのやる気がなくなってしまうので、今回はWEBエディター上でできる環境を用意しました。
以下のリンクを開いてください。
https://codesandbox.io/s/typescript-handson-step1-9ox24?fontsize=14&hidenavigation=1&theme=dark
これは有名なCodeSandboxというWEBエディターでクソほど便利なやつです。
個々のものとして開かれるので別に保存しても私の元のコードに影響は無いので安心してください。
srcフォルダ配下にpractice1.ts〜practice5.tsとtypeList.tsがあると思います。これらを使っていきます。
ちなみにtypeList.tsにはサンプルとして基本的な型の書き方が書いてあるので眺めてみてください。
プロローグ:JavaScriptの問題点
ではまずpractice1.tsを開き、右側の画面下にあるConsoleを押してください。
コンソールが表示されたかと思います。その状態で「練習問題1を実行」ボタンを押すと、practice1.tsの実行結果がコンソールに表示されます。このハンズオンではこのように各練習問題の実行結果をコンソールで確認できるようになっています。
ボタンを押した際にcalcTotalFeeという関数に1000という引数を渡し、1.1倍したものをコンソールに表示するというシンプルなものです。
では、少しコードをいじってみましょう。
引数の1000を文字列にしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 練習問題1 // calcTotalFeeの引数numにnumber型を設定し、 // 数値意外を引数に設定するとエラーになることを確認しよう const calcTotalFee = num => { const total = num * 1.1; console.log(`合計金額は${total}円です`); }; const el1 = document.getElementById("practice1"); // ↓ここの引数を変える el1.addEventListener("click", () => calcTotalFee("1000")); // ダブルクォーテーションで囲む |
Macならcommand + s、WindowsならCtrl + sで保存され自動にフォーマットが効くようになっています。
この状態で、関数を実行したらどうなるでしょうか?
文字列に1.1倍なんか計算できんけぇエラーになるんじゃないか?
残念!JavaScriptには「暗黙的な型変換」という機能が備わっているから文字型が数値型に変換されるんだよ
実際にコンソールに表示される結果も先程と同じだと思います。
では次は以下のように変更してみましょう。金額表示でよく見る形式ですね。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 練習問題1 // calcTotalFeeの引数numにnumber型を設定し、 // 数値意外を引数に設定するとエラーになることを確認しよう const calcTotalFee = num => { const total = num * 1.1; console.log(`合計金額は${total}円です`); }; const el1 = document.getElementById("practice1"); // ↓ここの引数を変える el1.addEventListener("click", () => calcTotalFee("1,000")); // カンマを入れる |
さぁこれはどうなるでしょうか?
これも暗黙的な型変換(ドヤ顔)されるから結果は一緒じゃな!
ざんねーん。これは数値には変換できないと判断されるから「合計金額はNaN円です」って表示されるんだな
NaNとは、「Not a Number」のことで、JavaScript特有のものです。数値に対して文字列をかけるなどおかしい計算をしたときにこうなってしまいます。
こういう「実行してみたらおかしかった」みたいなことをTypeScriptを導入することで防げるのです。
実際に世の中に出しているシステムだと本番環境で動かしてみて初めてエラーに気づくなんてことは避けたいですからね…
それでは上記のコードに型情報を付与していきましょう!!
練習問題1:引数の型指定
まずは関数の引数の型指定を学びます。
先程から見ているこちらのコードです。最初の状態に戻しましょう。
コメントに書いてある通り、calcTotalFeeの引数numにnumber型を設定してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 練習問題1 // calcTotalFeeの引数numにnumber型を設定し、 // 数値意外を引数に設定するとエラーになることを確認しよう const calcTotalFee = num => { const total = num * 1.1; console.log(`合計金額は${total}円です`); }; const el1 = document.getElementById("practice1"); // ↓ここの引数を変える el1.addEventListener("click", () => calcTotalFee(1000)); |
(〜〜考えてみてください〜〜)
正解は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 練習問題1 // calcTotalFeeの引数numにnumber型を設定し、 // 数値意外を引数に設定するとエラーになることを確認しよう const calcTotalFee = (num: number) => { const total = num * 1.1; console.log(`合計金額は${total}円です`); }; const el1 = document.getElementById("practice1"); // ↓ここの引数を変える el1.addEventListener("click", () => calcTotalFee(1000)); |
型を付与することで「()カッコ」が省略できなくなったのでカッコで囲むとこにも気をつけましょう。
この状態で、さっきNaNになったように引数を変更すると今度は事前にエラーが検知されます。
コーディング時にすぐおかしい箇所は分かるようになりました!型最高!!
練習問題2:返却値の型指定
次は関数の返却値の型指定もやっていきましょう。practice2.tsを開いてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 練習問題2 // calcTotalFee2の返却値にnumber型を設定すると、 // return部がエラーになることを確認しよう // 数値を返却するのが正しいようなので修正しよう const calcTotalFee2 = (num: number) => { const total = num * 1.1; return total.toString(); }; const dispTotalFee2 = (num: number) => { const total = calcTotalFee2(num); console.log(`合計金額は${total}円です`); }; const el2 = document.getElementById("practice2"); el2.addEventListener("click", () => dispTotalFee2(1000)); |
calcTotalFee2は今、toString()することで文字列を返却するようになっていますが、どうやら数値を返すのが正しいようです。
他の人がミスしないように数値型を返却することを明示して、数値を返却するように修正しましょう。
(〜〜考えてみてください〜〜)
正解は以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 練習問題2 // calcTotalFee2の返却値にnumber型を設定すると、 // return部がエラーになることを確認しよう // 数値を返却するのが正しいようなので修正しよう const calcTotalFee2 = (num: number): number => { const total = num * 1.1; return total; }; const dispTotalFee2 = (num: number) => { const total = calcTotalFee2(num); console.log(`合計金額は${total}円です`); }; const el2 = document.getElementById("practice2"); el2.addEventListener("click", () => dispTotalFee2(1000)); |
返却値の型は、引数のカッコのあとに:を書いて付与します。toString()を削除するのもお忘れなく。
これであとから他の人が勘違いしてtoString()みたいなことをすることがなくなりました!型最高!!
練習問題3:変数の型指定
次はシンプルに変数に型を指定してみましょう。practice3.tsを開きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 練習問題3 const calcTotalFee3 = (num: number) => { const total = num * 1.1; return total.toString(); }; // 変数totalにnumber型を設定すると、 // エラーになることを確認しよう // calcTotalFee3では数値を返却するのが正しいようなので修正しよう const dispTotalFee = (num: number) => { const total = calcTotalFee3(num); console.log(`合計金額は${total}円です`); }; const el3 = document.getElementById("practice3"); el3.addEventListener("click", () => dispTotalFee(1000)); |
11行目のtotalという変数にnumber型を付与していきます。結果的に意図しない型がcalcTotalFee3から返却されていることに気づくと思うので、先程同様修正してみましょう。
(〜〜考えてみてください〜〜)
正解はこちら。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 練習問題3 const calcTotalFee3 = (num: number): number => { const total = num * 1.1; return total; }; // 変数totalにnumber型を設定すると、 // エラーになることを確認しよう // calcTotalFee3では数値を返却するのが正しいようなので修正しよう const dispTotalFee = (num: number) => { const total: number = calcTotalFee3(num); console.log(`合計金額は${total}円です`); }; const el3 = document.getElementById("practice3"); el3.addEventListener("click", () => dispTotalFee(1000)); |
変数の型はシンプルに変数のあとに:をつけて指定します。calcTotalFee3側の修正は練習問題2と同じですね。
型をつけていくことで後からコードの修正をする人も事故する可能性がグンと減ります!型最高!!
練習問題4:設定ファイルを触ってみる
次は設定ファイルをいじっていきます。practice4.tsを開きます。
TypeScriptはtscofig.jsonという設定ファイルによってルールの厳密さや適用するものが設定されます。
つまりプロジェクトごとに合った設定ができるということですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 練習問題4 // tsconfigに"strict": trueを設定し // 1.エラーがでることの確認 // 2.コード修正による解決 // 3.設定変更による解決 // を試してみよう const calcTotalFee4 = num => { const total = num * 1.1; console.log(`合計金額は${total}円です`); }; const el4 = document.getElementById("practice4"); el4.addEventListener("click", () => calcTotalFee4(1000)); |
コメントに書いてあるようにstrictをtrueにしてみましょう。この設定は1番キッチリTypeScriptを使っていくときに使用するオプションで、いくつかの厳しめのルールが適用されるものです。
tsconfig.jsonを開き、以下のように追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "compilerOptions": { "module": "commonjs", "jsx": "preserve", "esModuleInterop": true, "sourceMap": true, "allowJs": true, "strict": true, "lib": [ "es7", "dom" ], "rootDir": "src", "moduleResolution": "node" } } |
保存し、再度practice4.tsを開くと以下のように先程はでていなかったエラーがでています。
anyというのはTypeScriptにおける「何でも屋」でどんな型でも受けつけまっせというものです。
明示的に: anyとしていない場合のanyがあると「危ないぜ」ってことでエラーになっています。
2枚目は「変数がnullになることあるかもよ!」っていうので怒ってくれています。
このように「”strict”: true」に設定することでより厳密にTypeScriptで開発をしていけます。
ん〜でもここまで厳しかったらちょっと嫌になるの〜
大丈夫、邪魔なルールはさっきのtsconfigで無効にすることができるから
tsconfig.jsonに以下を追記してみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "compilerOptions": { "module": "commonjs", "jsx": "preserve", "esModuleInterop": true, "sourceMap": true, "allowJs": true, "strict": true, "noImplicitAny": false, "strictNullChecks": false, "lib": [ "es7", "dom" ], "rootDir": "src", "moduleResolution": "node" } } |
保存して、practice4.tsを見てみるとさっきのエラーがなくなっていると思います。(うまく反映されない場合は保存して1度ブラウザをリロードしてみてください)
このようにプロジェクトに合った設定をしていけるの柔軟さもTypeScriptの魅力の1つです。
自分好みに設定できるなんて!型最高!!
練習問題5:高度な型指定
それでは最後にちょっと難易度の高い型指定を学んで入門編を終わりとしましょう。
practice5.tsを開きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 練習問題5(Literal Types & Union Types) // 2.allAnimalsに設定できる動物は「犬」or「猫」or「鳥」のみにしたい // allAnimalsに型を指定してみよう // ヒント:「犬」しか設定できない変数dogは、let dog: "犬" = "犬"と定義する let allAnimals = []; allAnimals.push("犬"); allAnimals.push("猫"); allAnimals.push("鳥"); allAnimals.push("亀"); // ←これをエラーにしたい const checkHasItem = item => { return allAnimals.includes(item) ? "ありました!" : null; }; const dispResult = (item: string) => { // 1.resultに入る可能性のある型はstringかnullのみなので明示したい // ヒント:stringかnumberの変数countは、let count: string | number = 0と定義する const result = checkHasItem(item); console.log(result); }; const el5 = document.getElementById("practice5"); el5.addEventListener("click", () => dispResult("犬")); |
2問含まれているので、まずは17行目の1.というほうを見てみましょう。
resultの型は「stringかnullのどちらか」ということなのでそのように指定してみましょう。
(〜〜考えてみてください〜〜)
正解はこうなります
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 練習問題5(Literal Types & Union Types) // 2.allAnimalsに設定できる動物は「犬」or「猫」or「鳥」のみにしたい // allAnimalsに型を指定してみよう // ヒント:「犬」しか設定できない変数dogは、let dog: "犬" = "犬"と定義する let allAnimals = []; allAnimals.push("犬"); allAnimals.push("猫"); allAnimals.push("鳥"); allAnimals.push("亀"); // ←これをエラーにしたい const checkHasItem = item => { return allAnimals.includes(item) ? "ありました!" : null; }; const dispResult = (item: string) => { // 1.resultに入る可能性のある型はstringかnullのみなので明示したい // ヒント:stringかnumberの変数countは、let count: string | number = 0と定義する const result: string | null = checkHasItem(item); console.log(result); }; const el5 = document.getElementById("practice5"); el5.addEventListener("click", () => dispResult("犬")); |
このように「|(パイプライン)」で繋ぐことで複数の型を指定できます。
どっちの型のパターンもある。というときはこのように指定していきます。
では次は3行目の問題。
allAnimalsという配列に「犬」「猫」「鳥」「亀」を追加していますが、この配列に入っても良い値は「犬」「猫」「鳥」のみにしたいということです。
allAnimalsは「犬」「猫」「鳥」しか入らない配列ですよ
という型を付与してみましょう。
(〜〜考えてみてください〜〜)
正解は、、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 練習問題5(Literal Types & Union Types) // 2.allAnimalsに設定できる動物は「犬」or「猫」or「鳥」のみにしたい // allAnimalsに型を指定してみよう // ヒント:「犬」しか設定できない変数dogは、let dog: "犬" = "犬"と定義する let allAnimals: Array<"犬" | "猫" | "鳥"> = []; allAnimals.push("犬"); allAnimals.push("猫"); allAnimals.push("鳥"); allAnimals.push("亀"); // ←これをエラーにしたい const checkHasItem = item => { return allAnimals.includes(item) ? "ありました!" : null; }; const dispResult = (item: string) => { // 1.resultに入る可能性のある型はstringかnullのみなので明示したい // ヒント:stringかnumberの変数countは、let count: string | number = 0と定義する const result: string | null = checkHasItem(item); console.log(result); }; const el5 = document.getElementById("practice5"); el5.addEventListener("click", () => dispResult("犬")); |
もしくは
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 練習問題5(Literal Types & Union Types) // 2.allAnimalsに設定できる動物は「犬」or「猫」or「鳥」のみにしたい // allAnimalsに型を指定してみよう // ヒント:「犬」しか設定できない変数dogは、let dog: "犬" = "犬"と定義する let allAnimals: ("犬" | "猫" | "鳥")[] = []; allAnimals.push("犬"); allAnimals.push("猫"); allAnimals.push("鳥"); allAnimals.push("亀"); // ←これをエラーにしたい const checkHasItem = item => { return allAnimals.includes(item) ? "ありました!" : null; }; const dispResult = (item: string) => { // 1.resultに入る可能性のある型はstringかnullのみなので明示したい // ヒント:stringかnumberの変数countは、let count: string | number = 0と定義する const result: string | null = checkHasItem(item); console.log(result); }; const el5 = document.getElementById("practice5"); el5.addEventListener("click", () => dispResult("犬")); |
のどちらでもOKです。配列は2つの型定義の仕方が可能で、
Array<型>
型[]
のどちらも可能です。(個人的には上がオススメです)
そして、string型ではなく、「犬」という文字しか入らないような変数の型は
1 2 3 |
const dog: "犬" = "犬"; |
のような型の指定が可能です。
これらを組み合わせた結果が先程のようなコードになるということです。
お疲れ様でした!以上で入門編のハンズオンは無事終了です(=´∀`)
TypeScriptおすすめ書籍
ちなみにTypeScriptの勉強には以下の本が超絶オススメです。バイブルです。
基本的な文法からReactとかVueで使う場合はどうするのか等も書いてあるのでまさに「実践」向きです。
実践TypeScript ~ BFFとNext.js&Nuxt.jsの型定義~ 新品価格 |
さいごに
以上TypeScriptの基礎の部分に触れてきました。
勉強会で口頭で説明しながらハンズオンした内容なので、説明が足らないとか分かりづらい部分もあるかもしれませんがご了承くださいm(._.)m
次回ののイベントでは応用編をやるので興味のある方は是非お越しください。
今回は型を付与してコードの安全性を高めていくのが主でしたが、TypeScriptの良さはコード補完にもあります。
その辺も応用編では触れていきたいと思います。
それでは!また!!
人気の記事だけ集めたので是非覗いていってください^^
厳選!目的別にオススメ記事を紹介-あなたの欲しい情報がここに-