本文へスキップ
スキルアップカレッジ

TypeScript とは何か——JavaScript に型を足す理由

レッスン1:TypeScript とは何か——JavaScript に型を足す理由

このレッスンで学ぶこと

  • 動的型付けの JavaScript で実務に起きる具体的な事故を説明できる
  • TypeScript が何をする言語で、JavaScript とどういう関係にあるかを説明できる
  • 本コースが扱う範囲と、扱わない範囲を理解する
  • 開発環境を整え、はじめてのコンパイルを実行できる
  • コース全体を通して繰り返し戻ってくる 6 つの中核メッセージを知る

JavaScript の基礎を学び終えた方は、変数・関数・配列・オブジェクトを使って、ある程度の分量のコードを書けるようになっているはずです。本レッスンでは、その先に待っている壁——コードが大きくなるにつれて起きる「事故」を先に見てから、TypeScript がそれにどう対処するのかを確認していきます。

静かに起きる、JavaScript の事故

コードが数十行のうちは、間違いがあってもすぐに気づけます。けれども、ファイルが増え、関数同士が呼び合うようになると、間違いは静かに紛れ込み、実行するまで表に出てきません。ここでは、動的型付けの JavaScript で実際に起きる 4 つの事故を見ていきます。

プロパティ名を 1 文字間違えても、コードは動いてしまう

オブジェクトのプロパティ名を綴り違えても、JavaScript はエラーにしません。

const user = {
  name: "森田 彩花",
  age: 30
};

console.log(user.nmae);

実行結果は次のとおりです。

undefined

nmae は存在しないプロパティです。人間なら「name の綴りが違う」とすぐ気づけますが、JavaScript にとってはただの「存在しないプロパティへのアクセス」でしかなく、エラーではなく undefined を返すだけで処理を続けます。この 1 行だけなら気づけても、100 行先で user.nmae の結果を使っていたら、原因を突き止めるのに時間がかかります。

undefined が紛れ込んでも、実行するまで気づけない

関数の呼び出し側が値を渡し忘れても、JavaScript は警告してくれません。

function calculateTotal(price, taxRate) {
  return price + price * taxRate;
}

console.log(calculateTotal(1000));

実行結果は次のとおりです。

NaN

taxRate を渡し忘れているため、関数の中では taxRate が undefined になります。1000 * undefined は NaN(Not a Number、数値でないことを表す値)になり、計算全体が壊れます。この関数がボタンのクリック処理の奥深くで呼ばれていたら、画面のどこに NaN が表示されているかを見て、ようやく原因を疑い始めることになります。

引数の順番を取り違えても、警告は出ない

関数の引数が増えてくると、順番の取り違えも起きやすくなります。

function createUser(name, age) {
  return { name: name, age: age };
}

const user = createUser(30, "森田 彩花");
console.log(user);

実行結果は次のとおりです。

{ name: 30, age: "森田 彩花" }

createUser は「名前、年齢」の順で受け取る関数ですが、呼び出し側は「年齢、名前」の順で渡してしまいました。JavaScript は数値と文字列のどちらも受け取れてしまうため、これもエラーにはなりません。データの中身が入れ替わったまま、後の処理に渡っていきます。

null の型が "object" になる、という仕様の落とし穴

「JavaScript 入門」で扱ったとおり、JavaScript には typeof null が "object" を返すという、歴史的な事情による仕様上の落とし穴があります。この 1 点だけでも、「値が本当は何なのか」を人間の注意力だけで正確に把握し続けるのは簡単ではないとわかります。

⚠️ 注意 ここまでの 4 つの事故に共通しているのは「エラーにならない」という点です。JavaScript はできる限り実行を止めずに処理を進めようとする性質を持っています。この柔軟さは学習のはじめには助けになりますが、コードが大きくなるほど、間違いを隠す方向にも働いてしまいます。

TypeScript とは何か

TypeScript は、Microsoft が開発した言語で、JavaScript に静的な型付けを加えたものです。「静的な型付け」とは、プログラムを実行する前の段階で、値の型(文字列なのか数値なのかオブジェクトなのか)をチェックする仕組みのことです。

TypeScript の重要な性質として、JavaScript のコードはそのまま TypeScript として扱えるという点があります。これを「上位互換」と呼びます。つまり、これまで JavaScript で書いてきたコードの知識は、TypeScript を学ぶうえでそのまま土台になります。ファイルの拡張子を .js から .ts に変え、必要な箇所に型注釈を足していく、というのが TypeScript を導入する基本の流れです。

💡 ポイント TypeScript は新しいプログラミング言語というより、「JavaScript に型チェックという安全装置を足したもの」と捉えるのが実態に近い理解です。書き方の大部分は JavaScript と共通しています。

TypeScript でこれらの事故がどう変わるか

先ほどの 3 つの事故を、TypeScript で型注釈を足して書き直すとどうなるかを見てみましょう。詳しい書き方はレッスン2 以降で扱うので、ここでは「型を書くと、こう変わる」という雰囲気だけをつかんでください。

type User = {
  name: string;
  age: number;
};

const user: User = {
  name: "森田 彩花",
  age: 30
};

console.log(user.nmae);

このコードをコンパイル(後述する、TypeScript を JavaScript に変換する処理)しようとすると、実行される前に次のようなメッセージが表示されます。

error TS2551: Property 'nmae' does not exist on type 'User'. Did you mean 'name'?

「nmae というプロパティは型 User には存在しません。name の間違いではありませんか」と、コードを実行する前の段階で教えてくれます。引数の順番の取り違えも同じように防げます。

function createUser(name: string, age: number) {
  return { name: name, age: age };
}

const user = createUser(30, "森田 彩花");

これも実行前に、次のようなメッセージが表示されます。

error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

「数値型の引数は、文字列型のパラメータには渡せません」という指摘です。実行して画面を確認する前に、書いている最中に間違いが見つかります。

💡 ポイント ここで押さえておきたいのは「エラーは実行する前に見つけたほうが安い」という考え方です。書いている最中に見つかる間違いは、修正のコストが小さくて済みます。画面に表示されてから、あるいは利用者からの問い合わせで気づく間違いは、原因を探すところから始めなければならず、コストがずっと大きくなります。

TypeScript の位置づけ——JavaScript の上位互換

TypeScript のコードは、そのままではブラウザや Node.js で実行できません。TypeScript を書いたら、それを JavaScript に変換する「コンパイル」という工程を経てから実行します。この変換を行う道具が TypeScript コンパイラで、コマンドラインでは tsc という名前で使います。

flowchart LR
    A[TypeScript のコードを書く] --> B[型チェックとコンパイル]
    B -->|型の間違いなし| C[JavaScript のコードが生成される]
    B -->|型の間違いあり| D[実行前にエラーで知らせる]
    C --> E[ブラウザや Node.js で実行]

この図は、TypeScript のコードが実行に至るまでの流れを表しています。型チェックの段階で間違いがあれば、そこで止まって知らせてくれます。問題がなければ、見慣れた JavaScript のコードが生成され、そこから先は今までどおりに実行されます。TypeScript は「実行する言語」というより「実行前にチェックしてから JavaScript を吐き出す道具」と捉えると、位置づけがつかみやすくなります。

本コースが扱う範囲と、譲る範囲

学習を始める前に、本コースの立ち位置をはっきりさせておきます。本コースが主に扱うのは「型システム」そのものと、JavaScript 入門コースが扱っていない「class・module」の 2 つです。次のような話題は、それぞれ専門に扱う入門コースに譲ります。

  • CSS の書き方・グリッドレイアウト・命名規則は、CSS 設計関連の入門コースが専門です
  • 業務の自動化やノーコードでの開発は、ノーコード関連の入門コースが専門です
  • 変数・条件分岐・繰り返し・配列・オブジェクトの基本文法は、JavaScript の基礎を扱う入門コースがすでに扱っています

本コースでは、これらを前提知識として扱い、繰り返しの説明はしません。もし読み進める中で基本文法があいまいに感じる箇所があれば、いったん基礎に戻って確認してから、本コースへ戻ってくることをおすすめします。

開発環境を用意する

TypeScript を動かすには、いくつかの道具を用意します。ここでは最小限の手順だけを紹介します。

TypeScript のコンパイルには Node.js(ブラウザの外で JavaScript を動かす実行環境)と、そこに付属する npm(パッケージを管理する道具)を使います。Node.js がまだ入っていない場合は、公式サイトから入手してインストールしてください。

作業用のフォルダを新しく作り、その中でターミナルを開いて、次のコマンドを順に実行します。

mkdir ts-practice
cd ts-practice
npm init -y

npm init -y は、このフォルダを npm で管理するための設定ファイル package.json を作るコマンドです。続けて、TypeScript 本体をインストールし、設定ファイルを作ります。

npm install --save-dev typescript
npx tsc --init

--save-dev は「開発中だけ使う道具としてインストールする」という指定です。TypeScript は、コードを書くときには必要ですが、完成した JavaScript を実行するだけの環境には不要なため、このように分けておきます。npx は、インストールした道具をコマンドとして実行するための仕組みです。2 行目を実行すると、tsconfig.json という設定ファイルが作られます。中にはたくさんの設定項目がコメント付きで並んでいますが、入門段階ではほぼ初期状態のままで問題ありません。

🔰 初学者の方へ ここでの手順は「一度作れば、あとは同じフォルダの中でずっと使い回せる」ものです。毎回すべてやり直す必要はありません。うまく進まないときは、node -v や npm -v をターミナルに打ち込んで、Node.js と npm 自体が動くかどうかを先に確認してみてください。コマンドが見つからないと表示される場合は、インストール自体がまだ済んでいない可能性が高いです。

はじめてのコンパイル

環境が整ったところで、実際に TypeScript のファイルを書いてコンパイルしてみましょう。ts-practice フォルダの中に hello.ts というファイルを作り、次の内容を書きます。

const message: string = "はじめての TypeScript です";
console.log(message);

保存したら、ターミナルで次の 2 つのコマンドを順に実行します。

npx tsc hello.ts
node hello.js

1 行目でコンパイルします。エラーがなければ何も表示されず、同じフォルダの中に hello.js というファイルが新しく作られます。これが、TypeScript から変換された JavaScript のコードです。中身を開くと、型注釈の部分が取り除かれた、見慣れた JavaScript になっているはずです。2 行目でその hello.js を実行します。

はじめての TypeScript です

型注釈を書いて、コンパイルして、実行する。このリズムが TypeScript を書くときの基本サイクルです。試しに message へ文字列ではなく数値を代入するコードへ書き換えてから、もう一度 npx tsc hello.ts を実行してみてください。先ほどの 2 つの例と同じように、実行される前の段階で「number 型は string 型に代入できません」という趣旨のメッセージが表示されるはずです。手元のエディタで実際に試して、メッセージの文面を自分の目で確認しておくと、レッスン8 で扱うエラーメッセージの読み方にもつながります。

数値を文字列型の変数に入れようとしたことを、コンパイルの段階で教えてくれました。これが TypeScript の基本の動き方です。

コース全体を貫く 6 つの中核メッセージ

ここまでで、TypeScript がなぜ必要とされているかの土台が整いました。本コースでは、以下の 6 つの考え方を背骨として、各レッスンで繰り返し確認していきます。今の段階ですべてを理解できていなくても構いません。まずは一度目を通しておいてください。

  1. 型は書き手を縛るためではなく、読み手に意図を伝えるためにある:型注釈は制約というより、コードを読む人(未来の自分を含みます)への説明書です
  2. エラーは実行する前に見つけたほうが安い:書いている最中に見つかる間違いは、修正のコストが小さく済みます
  3. 型は全部書かなくてよい。推論に任せられるところは任せる:TypeScript は多くの場面で型を自動的に判断してくれます。詳しくはレッスン3 で扱います
  4. any は逃げ道であって、使うたびに型の恩恵が消える:型チェックを無効にする any という書き方があります。使いどころには注意が必要です。詳しくはレッスン2 で扱います
  5. インターフェースは「この形をしていること」だけを求める:名前ではなく形で通じ合う考え方です。詳しくはレッスン5 で扱います
  6. 型を足すのは一度に全部ではなく、端から少しずつでよい:既存のコードに型を導入するときの現実的な進め方です。詳しくはレッスン7 で扱います

🗂 現場のひとこと スクールで TypeScript を教え始めた当初、受講生から「型を全部きっちり書かないといけないんですよね」と聞かれることがよくありました。実際は逆です。書けば書くほど安全にはなりますが、まずは事故が起きやすい箇所——外部から来るデータや、複数人が触る関数の入り口——から少しずつ型を足していくほうが、挫折せずに続けられます。

まとめ

このレッスンでは、以下のことを学びました。

  • 動的型付けの JavaScript では、プロパティ名の綴り違い・undefined の紛れ込み・引数の順番の取り違えといった間違いが、エラーにならず静かに紛れ込む
  • TypeScript は Microsoft が開発した言語で、JavaScript に静的な型付けを加えたもの。JavaScript のコードはそのまま TypeScript として扱える上位互換の関係にある
  • TypeScript のコードは tsc(コンパイラ)によって JavaScript に変換されてから実行される。型の間違いは、この変換の段階で実行前に知らせてくれる
  • 本コースは型システムと class・module を主に扱い、CSS の書き方や業務自動化、JavaScript の基本文法はほかの入門コースに譲る
  • npm install --save-dev typescript と npx tsc --init で開発環境を整え、npx tsc ファイル名 でコンパイルできる
  • 本コースを貫く 6 つの中核メッセージを確認した

次のレッスンでは、型注釈の基本的な書き方を学びます。文字列・数値・真偽値・配列・オブジェクトに型を付ける方法と、型チェックを無効にしてしまう any の危険性を確認していきましょう。


確認クイズ

このレッスンの理解度をチェックしましょう。