Menu

TypeScriptとJavaScriptの違い: 比較表とサンプルで解説

TypeScriptとJavaScriptの違いは、実行前にチェックされる静的な型システムがあるかどうかです。構文、型チェッカーが見つけるバグ、ビルドの手順、実行速度、学習コスト、JavaScriptのプロジェクトを移行する方法を並べて比較します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

TypeScriptは、JavaScriptの上に静的な型システムを加えたものです。JavaScriptのプログラムはすべてTypeScriptの構文としても正しく、TypeScriptはそこに型注釈、コードの実行前にそれをチェックするコンパイラー、そして型を再び取り除くビルドの手順を加えます。実行時にはJavaScriptしかないので、両者の違いはすべて、リリース前に何がわかるかにあります。

JavaScriptで同じ関数を書くと、このコードから type Product = ...、: Product[]、: number を取り除いたものになります。型はコンパイラーとエディターに情報を加えるだけで、プログラムの動きは変えません。

TypeScriptとJavaScriptの違いを一覧で

JavaScriptTypeScript
型システム動的: 型は値に属し、実行時にしかわからない静的: 型は宣言または推論され、コンパイル時にチェックされる
型エラーが現れるときその行が実行されたとき(undefined、NaN、TypeError)入力中のエディターと、コンパイル時
動く場所ブラウザー、Node.js、Deno、Bunで直接同じ場所で、型を取り除いたあと
ビルドの手順不要tsc かバンドラー、または型を自分で取り除くランタイム
ファイル.js、.mjs、.cjs.ts、.mts、.cts、.tsx、それに型宣言の .d.ts
実行速度基準同じ: 出力はJavaScript
エディターのサポート推論された型とライブラリの型定義による補完(不完全なこともある)宣言した型による補完、名前の変更、「すべての参照を検索」
学習コスト低いJavaScriptに加えて型システム
標準TC39によるECMAScriptECMAScriptに追随するMicrosoftのオープンソースプロジェクト

同じコードを両方の言語で

JavaScriptの関数です。user がどんな形でなければならないかは、どこにも書かれていません。

function greeting(user) {
    return `Hello, ${user.firstName} ${user.lastName}`;
}

greeting({ firstname: "Ada", lastName: "Lovelace" });
// "Hello, undefined Lovelace", no error anywhere

TypeScript版では形を一度書くだけで、タイプミスはコードの実行前に報告されます。

interface User {
    firstName: string;
    lastName: string;
}

function greeting(user: User): string {
    return `Hello, ${user.firstName} ${user.lastName}`;
}

greeting({ firstname: "Ada", lastName: "Lovelace" });
// error TS2561: Object literal may only specify known properties,
// but 'firstname' does not exist in type 'User'. Did you mean to write 'firstName'?

構文の違いは型注釈だけです。TypeScriptは独自の宣言もいくつか加えます(interface、type、enum、Array<string> のようなジェネリクス、private のようなアクセス修飾子)が、文、演算子、組み込みオブジェクトはJavaScriptのものです。

JavaScriptでは見つからず、TypeScriptが見つけるもの

JavaScriptは黙って型を変換します。このバグは、常に文字列であるフォームの入力値でよく起こります。実行してコンパイラーの出力を見てください。

index.ts(7,17): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
  Type 'string' is not assignable to type 'number'.

JavaScriptならこれは実行され、010205 と表示されます。0 + "10" が文字列の連結になるからです。TypeScriptは、たとえば fromForm.map(Number) で文字列を変換するまでコンパイルを拒否します。エラーの Type 'string' is not assignable to type 'number'. は「string型をnumber型に代入できない」という意味です。

もう1つの大きな分類は、存在しないかもしれない値です。Array.prototype.find は一致するものがないと undefined を返し、TypeScriptはその場合の処理を求めます。

index.ts(8,13): error TS18048: 'user' is possibly 'undefined'.

普通のJavaScript版は、実行時に TypeError: Cannot read properties of undefined (reading 'name') でクラッシュします。TypeScriptでの直し方は、コンパイラーが指摘したケースを処理することです。

出力:

GRACE
no user with id 3

TypeScriptが見つけ ない もの: ロジックの誤り(間違った計算式でも型は正しい)と、実行時にプログラムに入ってくるデータに関すること全般です。User と型を付けたAPIのレスポンスが正しいかどうかは、それを送ったサーバー次第です。コードが実行されるときには型はもう消えているからです。そうしたデータは実行時のコードでチェックしてください。

TypeScriptでJavaScriptのライブラリを使う

出力はどのみちJavaScriptなので、npmのパッケージはすべてTypeScriptから使えます。パッケージの型は次の3つのどこかから来ます。

  • パッケージ自身が .d.ts ファイルを含んでいる。 活発にメンテナンスされているパッケージの多くはそうで、何も追加でインストールする必要はありません。
  • コミュニティのDefinitelyTypedプロジェクトの、別の @types パッケージ。 npm install --save-dev @types/lodash で lodash の型が加わります。
  • どこにもない。 その場合、strict がオンならインポート自体がエラーになります。
error TS7016: Could not find a declaration file for module 'lodash'. '/project/node_modules/lodash/lodash.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/lodash` if it exists or add a new declaration (.d.ts) file containing `declare module 'lodash';`

直し方は、@types パッケージがあればそれをインストールするか、.d.ts ファイルでモジュールを自分で記述することです。やり方は型定義ファイルのページで解説しています。

ビルドの手順

ブラウザーやNode.jsは型チェックをしないので、TypeScriptにはソースコードと実行されるコードの間にひと手間が必要です。よく使われる構成は3つあります。

  • tsc がすべてをコンパイルする。 型チェックをして、ふつうは dist フォルダーに .js ファイルを書き出します。シンプルで、ライブラリの標準的なやり方です。
  • バンドラーや開発サーバーが型を取り除き、tsc --noEmit がチェックする。 Viteやesbuildはチェックせずに型を取り除くので、再読み込みが速く保たれます。型チェッカーはエディターとCIのステップで実行します。
  • ランタイムが型を取り除く。 現在のNode.js、Deno、Bunは .ts ファイルを直接実行します。どれも実行中に型チェックはしないので、型エラーを見つけるにはやはり tsc --noEmit(または deno check)を使います。

JavaScriptにはこのどれも必要なく、それが小さなスクリプトでの一番の実用的な利点です。TypeScriptの手順のコストは、主に設定(tsconfig.json と開発用依存の typescript)とコンパイル時間です。TypeScript 7のネイティブコンパイラーは、大規模なプロジェクトでその時間をおよそ10分の1にしました。

学習コスト

TypeScriptの実行時の動きはJavaScriptなので、JavaScriptについて知っていることはすべてそのまま使えます。新しく学ぶのは型システムで、段階的に進められます。

  1. 変数、引数、戻り値への型注釈(: string、: number[])。
  2. interface と type によるオブジェクトの型、省略可能なプロパティ、string | number のようなユニオン型。
  3. 型の絞り込み: typeof、in、=== で値をチェックし、どのケースにいるかをコンパイラーに知らせる。
  4. ジェネリクス、Partial<T> や Pick<T, K> のようなユーティリティ型、ライブラリ作者向けの高度な型。

アプリケーションのコードの大部分は、最初の2段階でカバーできます。型の多くは推論されるので、TypeScriptのコードの多くは、関数のシグネチャにだけ注釈を付けたJavaScriptのように見えます。

TypeScriptとJavaScriptの使い分け

TypeScriptはJavaScriptより優れているのでしょうか。複数人で保守するコードや何年も使われるコードなら、たいていはそうで、業界もその方向に進んでいます。GitHubの月間コントリビューター数の集計では、TypeScriptは2025年8月にJavaScriptとPythonの両方を抜いて、GitHubで最も使われている言語になりました。小さなスクリプトなら、普通のJavaScriptのほうが適していることがよくあります。

TypeScript を選ぶのはこんなとき:

  • 複数人でコードを扱う、または数か月から数年保守する。
  • すべての関数のシグネチャを覚えていられないほどコードベースが大きい。
  • リファクタリングが多い。プロパティ名を変えるとすべての使用箇所が更新され、残りはコンパイラーが一覧にします。
  • ライブラリを公開する。.d.ts ファイルが利用者に補完とチェックを提供します。
  • フレームワークが前提にしている。AngularのアプリはTypeScriptで書かれ、Next.jsとAstroは新しいプロジェクトを標準でTypeScriptで作成し、ViteのReact・Vue・SvelteのテンプレートにはそれぞれTypeScript版があります。

JavaScript を選ぶのはこんなとき:

  • 短いスクリプト、使い捨ての実験、ブラウザーのコンソールで試すコード。
  • 初めてプログラミングを学んでいて、一度に覚える概念を減らしたい。
  • ビルドの手順がなく、加えたくもない。その場合でも、JSDocと // @ts-check を使えば普通の .js ファイルである程度のチェックができます。

JavaScriptのプロジェクトをTypeScriptに移行する

移行は一度に行う必要はありません。コンパイラーはTypeScriptと並んでJavaScriptも受け付けます。

{
    "compilerOptions": {
        "allowJs": true,
        "checkJs": false,
        "outDir": "dist",
        "rootDir": "src"
    },
    "include": ["src"]
}

allowJs を付けると .js ファイルもコンパイルされ、.ts ファイルからインポートすることも、その逆もできます。あとは少しずつ変換します。

  1. ファイルを1つ .js から .ts に名前を変え、そこでコンパイラーが報告するエラーを直す。
  2. 末端(インポートの少ないユーティリティのモジュール)から始めて、内側へ進む。
  3. checkJs をオンにするか、個々の .js ファイルの先頭に // @ts-check を加えて、まだ名前を変えていないファイルも型チェックする。

チェック対象のJavaScriptファイルでは、JSDocコメントが型を与えます。

// @ts-check

/**
 * @param {number} price
 * @param {number} qty
 * @returns {number}
 */
function lineTotal(price, qty) {
    return price * qty;
}

lineTotal("3", 2);
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

そこで止めるチームもあります。JSDocの型を持つJavaScriptファイルを tsc でチェックし、コード自体のビルドの手順は持たないやり方です。すべてを .ts にするチームもあります。既存のプロジェクトで strict をオンにすると、最初は大量のエラーが出ると考えてください。strictモードのページに各フラグが何をチェックするかがまとめてあるので、1つずつ有効にしていけます。

よくある質問

TypeScriptとJavaScriptの主な違いは何ですか?

TypeScriptはJavaScriptに静的な型を加えます。それぞれの値が何かを書き(name: string、items: Item[])、TypeScriptのコンパイラーがコードの実行前にミスを報告します。JavaScriptは事前に何もチェックしません。型の間違いはその行が実行されたときにだけ現れ、たいていは undefined や TypeError になります。

TypeScriptはJavaScriptより優れていますか?

複数人で保守するプロジェクトや、数週間以上使われるプロジェクトの多くでは、そうです。型はさまざまな種類のバグを見つけ、リファクタリングを安全にし、エディターの補完を支えます。短いスクリプト、手早いプロトタイプ、学習用の練習なら、普通のJavaScriptのほうがすぐに始められ、ビルドの設定もいりません。

TypeScriptはJavaScriptより速いですか?

いいえ。遅くもありません。TypeScriptはJavaScriptにコンパイルされ、型は消去されるので、実行されるのは手で書くのと同じJavaScriptです。追加のコストは開発中のコンパイル時間だけです。

JavaScriptとTypeScriptのどちらを先に学ぶべきですか?

JavaScriptの基本を先に、またはTypeScriptと一緒に学びましょう。実行時の動き(変数、関数、オブジェクト、配列、Promise)はすべてJavaScriptで、TypeScriptはそれを記述するだけです。小さなJavaScriptのプログラムを書けるようになれば、型を加えるのはすぐです。

同じプロジェクトでTypeScriptとJavaScriptを一緒に使えますか?

使えます。tsconfig.json で "allowJs": true を設定すると、コンパイラーは .ts ファイルと並んで .js ファイルも受け付けます。"checkJs": true(またはファイルごとの // @ts-check コメント)を加えると、JSDocコメントの型を使ってJavaScriptのファイルも型チェックされます。これがプロジェクトをファイルごとに移行するふつうの方法です。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める