ポートフォリオを
TypeScript にしよう
Lesson 9 で、JavaScript を使ってポートフォリオに動きを付けました。今回はそのスクリプトを、 現場でとてもよく使われている TypeScript(タイプスクリプト)に書き換えます。 見た目も動きも同じまま、「間違いに気づきやすいコード」に生まれ変わらせるのがゴールです。
1. TypeScriptとは
TypeScript は、Microsoft が開発した、JavaScript に「型(かた)」というルールを足した言語です。 JavaScript の書き方はほぼそのまま使えて、そこに「この箱には何を入れるか」というラベルを書き足していきます。
JavaScript の箱
どんなものでも入れられる、ラベルのない箱。数字を入れていた箱に、うっかり文字を入れても何も言われません。
let angle = 0;
angle = "ごど"; // 文字を入れても、何も言われないTypeScript の箱
「数字専用」とラベルを貼った箱。数字以外を入れようとすると、その場で「それは入れられません」と教えてくれます。
let angle: number = 0;
angle = "ごど"; // ← エラー!「数字専用」の箱です
: number の部分が型です。キッチンの調味料の容器に「砂糖」「塩」とラベルを貼っておけば、取り違えを防げますよね。型はそのラベルのようなものです。
| 型 | 意味 | 例 |
|---|---|---|
number | 数字 | 0、5、3.14 |
string | 文字(文字列) | "こんにちは!" |
boolean | はい/いいえ | true、false |
string[] | 文字のリスト(配列) | ["A", "B", "C"] |
2. 何がうれしいの?
JavaScript では、間違いに気づくのはブラウザで動かしてみたときです。しかも、エラーにならずに「なんだか変な動き」になるだけのこともあります。 TypeScript なら、コードを書いている最中に、VS Code が赤い波線で間違いを教えてくれます。
JavaScript の場合
書く → 保存 → ブラウザで確認 → 「あれ、動かない……」→ コンソールで原因を探す
TypeScript の場合
書いた瞬間に VS Code が「ここ、おかしいですよ」と赤い波線で教えてくれる
数百行のポートフォリオなら JavaScript でも困りませんが、何十人もの PG が何万行ものコードを書く実際のシステム開発では、この差がとても大きくなります。 そのため、フロントエンドエンジニアの現場では、今や TypeScript で書くのが当たり前になりつつあります。
3. ブラウザは TypeScript を読めない
実は、ブラウザが理解できるのは JavaScript だけです。そのため、TypeScript で書いたファイルは、 コンパイラ(翻訳ツール)で JavaScript に変換してから使います。この変換をコンパイルと呼びます。
(型のラベル付き)
JavaScript に変換
読み込んで動かす
英語の原稿を翻訳者にチェック・翻訳してもらってから、日本語版を印刷するイメージです。翻訳者(tsc)は、原稿の間違い(型のミス)も指摘してくれます。
4. 準備:Node.js と TypeScript を入れる
コンパイラ tsc を使うために、Node.js(ブラウザの外で JavaScript を動かす仕組み)と、
その付属ツール npm(便利なツールをダウンロードする仕組み)を使います。
会社のパソコンにインストールするときは、Lesson 6 と同じく社内のルールに従ってください。
-
Node.js をインストールする
Chrome で
https://nodejs.org/を開き、LTS(長期サポート版)の Windows 用インストーラーをダウンロードして実行します。 基本的には「Next」で進めて大丈夫です。途中の「Tools for Native Modules」のチェックは入れなくてかまいません。 -
インストールできたか確認する
VS Code をいったん閉じて開き直し、ターミナルで次の2つを実行します。それぞれバージョン番号が表示されれば成功です。
ターミナルnode -v npm -v -
portfolio フォルダを npm 用に準備する
VS Code で
portfolioフォルダを開いた状態で、ターミナルに次のコマンドを入力します。package.jsonというファイルができます。ターミナルnpm init -y -
TypeScript をインストールする
ターミナルnpm install --save-dev typescriptnode_modulesというフォルダができ、その中に TypeScript のコンパイラがダウンロードされます。このフォルダの中身は触らなくて大丈夫です。 -
設定ファイル tsconfig.json を作る
portfolioフォルダに新しいファイルtsconfig.jsonを作り、次の内容を書きます。「どのファイルを、どんなルールで変換するか」の設定です。tsconfig.json{ "compilerOptions": { "target": "ES2020", "lib": ["ES2020", "DOM"], "strict": true }, "files": ["script.ts"] }設定 意味 "target": "ES2020"どのバージョンの JavaScript に変換するか "lib": ["ES2020", "DOM"]documentなど、ブラウザの機能を使えるようにする"strict": true型のチェックを厳しくする(間違いを見つけやすくなる) "files": ["script.ts"]変換するファイル
| うまくいかないときは | 確認すること |
|---|---|
node や npm が見つからないと言われる | Node.js のインストール後に、VS Code を開き直したか確認してください。 |
| 「このシステムではスクリプトの実行が無効になっているため…」と出る | PowerShell の安全設定によるものです。VS Code のターミナル右上の「+」の横の「∨」から「Command Prompt」を選んでターミナルを開き直し、同じコマンドを実行してみてください。 それでもだめな場合は、情報システム担当者に相談してください。 |
5. script.js を TypeScript に書き換える
まずはファイル名を変えるだけ
VS Code で script.js を右クリック →「名前の変更」で、script.ts に変えます(.ts は TypeScript の印)。
すると、さっそくいくつかの行に赤い波線が出るはずです。波線の上にマウスを乗せると、こんなメッセージが表示されます。
'greeting' は 'null' の可能性があります。
これは、「getElementById("greeting") で探しても、見つからないかもしれないよね? 見つからなかったら(null=空っぽ)、
greeting.textContent の行でエラーになりますよ」という指摘です。
JavaScript では、名札の名前を打ち間違えても、ブラウザで動かすまで気づけませんでした。TypeScript は、その可能性を書いている時点で教えてくれるわけです。
① あいさつ:「必ずある」と伝える、型を書く
// ① 時間帯に合わせて、あいさつを変える
const greeting = document.getElementById("greeting") as HTMLElement;
const hour: number = new Date().getHours();as HTMLElement:「この名札の部分は、HTML に必ずあります。HTML の部品(HTMLElement)として扱ってください」と TypeScript に伝える書き方です。これで赤い波線が消えますhour: number:「hourの箱には数字を入れます」というラベル
as は「私が保証します」という約束なので、本当に HTML に id="greeting" があるかは自分で確認しておく必要があります。
本格的な開発では if (greeting) { … } のように「あるときだけ動かす」書き方もよく使われます。
② 鉄棒:箱にラベルを貼る
// ② 鉄棒の人が、くるくる回り続ける
const person = document.getElementById("person") as HTMLImageElement;
const tetsubo = document.getElementById("tetsubo") as HTMLElement;
let angle: number = 0;
let moving: boolean = true;
setInterval(function (): void {
if (moving) {
angle = angle + 5;
person.style.transform = "rotate(" + angle + "deg)";
}
}, 30);
tetsubo.addEventListener("click", function (): void {
moving = !moving;
});HTMLImageElement:画像(<img>)の部品、という型。personは画像なので、より詳しい型を付けていますlet angle: number・let moving: boolean:角度は数字、動いているかどうかは「はい/いいえ」function (): void:voidは「この処理は何も返さない(やるだけ)」という意味の型
③④ コントローラーとひとこと:同じ処理を「関数」にまとめる
Lesson 9 では、③ と ④ の両方で「ランダムに番号を選ぶ」処理(Math.floor(Math.random() * …))を書いていました。
せっかくなので、これを1つの関数にまとめて、型も付けてみましょう。script.ts の一番上に書きます。
// 0〜(length - 1) のどれかの番号を、ランダムに選ぶ
function pickRandomIndex(length: number): number {
return Math.floor(Math.random() * length);
}function pickRandomIndex( … ):「ランダムな番号を選ぶ」という名前の、自分専用の命令(関数)を作る(length: number):この関数には、数字を1つ渡して使う(例:pickRandomIndex(4))): number {:この関数は、数字を返すreturn …:計算した結果を返す
あとは、③ と ④ でこの関数を使うように書き換えます。
// ③ コントローラーのボタンが、ポチポチ光る
const padButtons = document.querySelectorAll(".pad-button");
setInterval(function (): void {
const padButton = padButtons[pickRandomIndex(padButtons.length)];
padButton.classList.add("pressed");
setTimeout(function (): void {
padButton.classList.remove("pressed");
}, 200);
}, 350);// ④ ボタンを押すと、ひとことがランダムに変わる
const messages: string[] = [
"最近はエアロピクルスも好きだよ",
"スーの歌も好きだよ",
"ねずみなんだけど丑年なんでスー"
];
const message = document.getElementById("message") as HTMLElement;
const messageButton = document.getElementById("message-button") as HTMLButtonElement;
messageButton.addEventListener("click", function (): void {
message.textContent = messages[pickRandomIndex(messages.length)];
});pickRandomIndex("4") のように数字ではなく文字を渡したり、返ってきた番号を文字の箱に入れようとしたりすると、TypeScript がすぐに教えてくれます。
関数は「たくさんの場所から使われる部品」なので、使い方のルール(型)が書いてあると、他の人が使うときにも迷いません。
書き換えが終わった script.ts の全体はこちらです。
// 0〜(length - 1) のどれかの番号を、ランダムに選ぶ
function pickRandomIndex(length: number): number {
return Math.floor(Math.random() * length);
}
// ① 時間帯に合わせて、あいさつを変える
const greeting = document.getElementById("greeting") as HTMLElement;
const hour: number = new Date().getHours();
if (hour < 10) {
greeting.textContent = "おはようございます!";
} else if (hour < 18) {
greeting.textContent = "こんにちは!";
} else {
greeting.textContent = "こんばんは!";
}
// ② 鉄棒の人が、くるくる回り続ける
const person = document.getElementById("person") as HTMLImageElement;
const tetsubo = document.getElementById("tetsubo") as HTMLElement;
let angle: number = 0;
let moving: boolean = true;
setInterval(function (): void {
if (moving) {
angle = angle + 5;
person.style.transform = "rotate(" + angle + "deg)";
}
}, 30);
tetsubo.addEventListener("click", function (): void {
moving = !moving;
});
// ③ コントローラーのボタンが、ポチポチ光る
const padButtons = document.querySelectorAll(".pad-button");
setInterval(function (): void {
const padButton = padButtons[pickRandomIndex(padButtons.length)];
padButton.classList.add("pressed");
setTimeout(function (): void {
padButton.classList.remove("pressed");
}, 200);
}, 350);
// ④ ボタンを押すと、ひとことがランダムに変わる
const messages: string[] = [
"最近はエアロピクルスも好きだよ",
"スーの歌も好きだよ",
"ねずみなんだけど丑年なんでスー"
];
const message = document.getElementById("message") as HTMLElement;
const messageButton = document.getElementById("message-button") as HTMLButtonElement;
messageButton.addEventListener("click", function (): void {
message.textContent = messages[pickRandomIndex(messages.length)];
});6. JavaScript に変換して動かす
-
コンパイルする
ターミナルで次のコマンドを実行します。
npxは「このフォルダにインストールしたツールを実行する」ためのコマンドです。ターミナルnpx tsc何も表示されずに終われば成功です(エラーがあると、ここで表示されます)。
portfolioフォルダに、変換されたscript.jsができています。 -
ブラウザで確認する
index.htmlを Chrome で開きます。index.htmlは何も変えていません。 これまでどおりscript.jsを読み込むので、鉄棒もコントローラーもひとことも、Lesson 9 と同じように動けば成功です。
できあがった script.js の最初のほうを見てみると、: number や as HTMLElement などの型の部分が、きれいに消えているのがわかります。
"use strict";
// 0〜(length - 1) のどれかの番号を、ランダムに選ぶ
function pickRandomIndex(length) {
return Math.floor(Math.random() * length);
}
// ① 時間帯に合わせて、あいさつを変える
const greeting = document.getElementById("greeting");
const hour = new Date().getHours();script.ts の方を編集します。script.js はコンパイルのたびに上書きされるので、直接書き換えても消えてしまいます。
script.ts を直したら、そのたびに npx tsc を実行しましょう。
毎回コマンドを打つのが面倒なら
次のコマンドを実行しておくと、script.ts を保存するたびに自動でコンパイルしてくれます(止めるときは Ctrl + C)。
npx tsc --watch
さらに、package.json の "scripts" を次のように書き換えておくと、npm run build(1回変換)・npm run watch(自動で変換)という短い名前で実行できます。
多くの開発現場で使われている書き方です。
"scripts": {
"build": "tsc",
"watch": "tsc --watch"
},Lesson 9 のときと比べて、フォルダの中身はこう変わりました。
portfolio/
├── index.html
├── style.css
├── script.js ← 自分で書く JavaScript
└── images/portfolio/
├── index.html
├── style.css
├── script.ts ← 自分で書く TypeScript
├── script.js ← tsc が自動で作る(編集しない)
├── tsconfig.json ← TypeScript の設定
├── package.json ← npm の設定
├── node_modules/ ← ダウンロードしたツール(触らない)
└── images/オレンジの script.js が、緑の script.ts に置き換わりました。
- 自分で書くファイルが、
script.jsからscript.tsに変わります(中身は 5章で書き換えたとおり)。 script.jsはなくなるわけではなく、tsc がscript.tsから自動で作るファイルになります。index.htmlがこれを読み込むので、HTML は変えなくてOKです。- 増えた
tsconfig.json・package.json・node_modules/は、TypeScript を使うための道具と設定です。
7. わざと間違えてみよう
TypeScript のありがたみを体験するために、script.ts の ② の部分を、わざと次のように書き換えてみてください。
angle = angle + "5";すぐに VS Code が赤い波線を出し、npx tsc を実行すると次のエラーが表示されます。
script.ts(26,5): error TS2322: Type 'string' is not assignable to type 'number'.VS Code の日本語表示では「型 'string' を型 'number' に割り当てることはできません。」と表示されます。(26,5) は「26行目の5文字目」という意味です(行番号は書き方によって変わります)。
「数字専用の箱(angle)に、文字("5")をくっつけたものは入れられません」という意味です。
JavaScript だと、エラーにならずに 0 と "5" がくっついて "05" という文字になり、
「なぜか鉄棒の人の回り方がおかしい……」という原因のわかりにくいバグになってしまいます。
確認できたら、angle = angle + 5; に戻しておきましょう。
Claude Code にも聞いてみよう
型のエラーは、慣れるまでメッセージが難しく感じます。そんなときは Claude Code に聞いてみましょう。
script.ts で「'greeting' は 'null' の可能性があります。」というエラーが出ました。
どういう意味か、初心者にもわかるように説明してください。直し方は2通り教えてください。確認クイズ
選択肢をクリックしてください。
Q1. TypeScript は、JavaScript に何を足した言語?
Q2. let moving = true; の moving に付ける型は?
Q3. ブラウザで TypeScript のコードを動かすには、どうする?
Q4. TypeScript にしたあと、プログラムを直したいときに編集するファイルは?
Q5. TypeScript を使うと、型の間違いにいつ気づける?
まとめ
- TypeScript は、JavaScript に「型」というラベルを足した言語。
number・string・booleanなどがある。 - 型があると、書いている最中に間違いに気づける。大人数・大規模な開発ほど効果が大きい。
- ブラウザは TypeScript を読めないので、tsc で JavaScript にコンパイルしてから使う。
- 準備は Node.js →
npm init -y→npm install --save-dev typescript→tsconfig.json。 - 編集するのは
script.ts。直したらnpx tsc(またはnpx tsc --watch)。 - 同じ処理は関数にまとめ、引数と戻り値に型を付けると、安全で使いやすい部品になる。