Skip to content

MS_TypeScript

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

TypeScript

概要

OSS

  • オープンソース。ライセンスは Apache License 2.0。

AltJS

  • ECMAScript 6 規格

    • JavaScript のスーパーセット
    • 静的型付けな JavaScript
    • クラス・インターフェイスとその継承
    • 内部モジュールなどなど。
    • Java に近い記述が採用
  • JavaScript を生成する。

    • コンパイルすると JavaScript に変換される。
    • 変換後の JavaScript も読み易い。

Microsoft

  • Microsoft が開発。
  • Visual Studio でサポートされる。
  • C# 作者が開発している。

その他

  • 拡張子は *.ts、*.tsx
  • 仕組は、npm(DNET_npm.md)などの Node.js 系ツールと同じ。

補足(AltJS 競争の勝者になった): 原文が書かれた頃、
**TypeScript は「AltJS の 1 つ」**という位置付けだった。
現在は事実上の標準である。

【AltJS(JavaScript に代わる言語)の変遷】

   CoffeeScript(2009)… 簡潔な記法。【ES6 が同等の機能を取り込み消滅】
   Dart(2011)        … Google 製。Web では普及せず、【Flutter で復活】
   TypeScript(2012)  … 【型を足しただけ】★ 勝った
   Elm、PureScript 等   … 関数型。ニッチに残る
   Babel + Flow(2014) … Facebook 製の型注釈。【TypeScript に敗れた】

なぜ TypeScript が勝ったのか:

理由 内容
スーパーセットである 既存の .js をそのまま .ts に改名して動く。段階的に導入できる ★
標準を追いかけた 独自機能を作らず、ECMAScript の仕様に追随async/await 等)
型だけ足した 実行時の挙動を変えない(型は消えるだけ)
エコシステム DefinitelyTyped で既存ライブラリに型が付いた
IDE 体験 補完・リファクタリング・エラー検出が段違い

「型を足しただけ」が決定的である。
CoffeeScript や Dart は新しい言語を覚えさせたが、
TypeScript は**「JavaScript を書けるなら、もう書ける」**と言えた。

移行メモ(「ECMAScript 6 規格」という記述): 原文の
「ECMAScript 6 規格」は、執筆当時の対応状況を指している。
現在の TypeScript は、

・ECMAScript の【最新提案まで】追随している
・出力先(target)は ES5 ~ ESNext まで選べる
・むしろ【ECMAScript より先に機能を実装】することもある
   (decorators、enum 等。ただし標準化とずれるリスクもある)

**「C# 作者が開発している」**という記述の通り、
Anders Hejlsberg 氏(Turbo Pascal、Delphi、C# の設計者)が
TypeScript の設計を主導した。
C# 開発者にとって学習コストが低いのは偶然ではない。

書き方

型注釈

http://goo.gl/jKVeHw

クラス

http://goo.gl/l3zjBi

インタフェース

http://goo.gl/GQD89G

内部モジュール

http://goo.gl/gvjgTU

ジェネリクス

アロー関数式(≒ラムダ式

移行メモ(短縮 URL について): 本節のリンクは
goo.gl の短縮 URL だが、
Google URL Shortener は 2019 年に新規発行を停止し、
2025 年に既存リンクの解決も終了
した。
したがってこれらのリンクは現在たどれない

代わりに、公式ハンドブックの該当箇所を挙げておく

項目 現在の参照先
型注釈 https://www.typescriptlang.org/docs/handbook/2/everyday-types.html
クラス https://www.typescriptlang.org/docs/handbook/2/classes.html
インタフェース https://www.typescriptlang.org/docs/handbook/2/objects.html
内部モジュール(namespace) https://www.typescriptlang.org/docs/handbook/namespaces.html
ジェネリクス https://www.typescriptlang.org/docs/handbook/2/generics.html
関数 https://www.typescriptlang.org/docs/handbook/2/functions.html

短縮 URL を文書に残さない——というのは、
本 Wiki のような長期保存を前提とした資料では重要な教訓である。

補足(C# 開発者のための対応表): C# と似ているが、
決定的に違う点がある
ので整理しておく。

概念 C# TypeScript
型注釈 int x = 1; let x: number = 1;(型は後ろ)
型推論 var x = 1; let x = 1;(既定で推論される)
クラス class A : B, IC class A extends B implements IC
インターフェイス 実装を宣言する必要がある 構造が合えば実装扱い(構造的部分型)★
ジェネリクス List<T> Array<T> / T[]
ラムダ x => x * 2 x => x * 2(同じ)
null 許容 string? string | null(共用型)
名前空間 namespace ESM の import/export

**最大の違いは「構造的部分型(Structural Typing)」**である。

interface Point { x: number; y: number; }

// implements と書いていないのに、Point として通る ★
const p = { x: 1, y: 2 };
function draw(pt: Point) { }
draw(p);          // OK
draw({x:1, y:2, z:3});  // OK(余分なプロパティも構造としては満たす)
【C#(公称型 / Nominal Typing)】
   「Point を実装すると宣言した型」だけが Point

【TypeScript(構造的部分型 / Structural Typing)】
   「Point と同じ形をしていれば」Point ★

 → JavaScript のオブジェクトが元々そういうものだから、こうなった
 → 【C# の感覚で読むと戸惑う】最大のポイント

もう 1 つの重要な違い:型は実行時に消える

interface User { name: string; }

// ✗ C# のようには書けない(実行時に User は存在しない)
if (obj instanceof User) { }        // コンパイル エラー

// ○ 型ガードを自分で書く
function isUser(o: unknown): o is User {
    return typeof o === 'object' && o !== null && 'name' in o;
}
【型消去(Type Erasure)】
   tsc は【型を取り除いて JavaScript を出力するだけ】
     → 実行時の型チェックは【一切行われない】★
     → API から受け取った JSON が型どおりである保証はない

【対策】 実行時検証ライブラリを併用する
   Zod、Valibot、io-ts 等
     → スキーマから【型と検証を同時に得る】
import { z } from 'zod';
const UserSchema = z.object({ name: z.string(), age: z.number() });
type User = z.infer<typeof UserSchema>;   // 型が自動導出される
const user = UserSchema.parse(await res.json());  // 実行時に検証される ★

namespace(内部モジュール)は現在は非推奨である。

・原文の時代は namespace が普通だった(モジュール システムが未成熟)
・現在は【ESM(import / export)】を使う ★
・namespace はグローバルを汚し、ツリー シェイキングも効かない

チートシート

TypeScriptの基本的な言語仕様:

  • 変数の型注釈と型推論
  • クラスを利用する
  • get/set アクセサを利用する
  • インタフェース
  • enum(列挙型)
  • オブジェクト型リテラル
  • いろいろな型注釈の書き方
  • 構造的部分型
  • 総称型(ジェネリクス)
  • namespace(内部モジュール)
  • アロー関数式
  • コンストラクタと引数プロパティ宣言
  • アンビエント宣言
  • 型定義ファイル
  • 可変長引数
  • 省略可能引数とデフォルト値付き引数
  • public と private と protected
  • オーバーロード
  • 型アサーション
  • 型クエリ
  • 外部モジュール
  • タプル型
  • 共用型
  • type alias(型の別名)

TypeScriptとECMAScript 2015(6)、7:

  • let/const
  • template literals
  • shorthand properties
  • destructuring
  • spread operator
  • ES6 modules
  • for...of
  • symbols
  • computed properties
  • decorators

補足(この一覧以降に追加された主な機能): チートシートは
TypeScript 1.5 対応であり、
その後の追加が非常に多い。実務でよく使うものを挙げる。

機能 内容
2.0 strictNullChecks null / undefined を型で区別する
2.1 mapped types / keyof Partial<T>Readonly<T>
2.8 conditional types T extends U ? X : Y
3.0 unknown 型 any より安全な「何か」
3.7 optional chaining / nullish coalescing a?.ba ?? b(C# と同じ記法)
4.1 template literal types 文字列の型を組み立てる
4.9 satisfies 演算子 型を狭めずに検査する
5.0 decorators(標準版) ECMAScript 標準に沿った実装
5.x const 型パラメータ ほか

strictNullChecks が最重要である。

// strictNullChecks: false(旧既定)
let s: string = null;       // 通ってしまう ✗

// strictNullChecks: true(現在の推奨)
let s: string = null;       // エラー ★
let s2: string | null = null;  // 明示すれば OK
【C# の null 許容参照型と同じ発想】
   C#  : <Nullable>enable</Nullable> → string? と string を区別
   TS  : strictNullChecks: true      → string | null と string を区別

 → どちらも【後から追加された】ため、既存コードでは無効なことが多い
 → 新規プロジェクトでは【必ず有効にする】★

anyunknown の使い分け:

// any … 型チェックを【放棄する】。何でもできてしまう
let a: any = JSON.parse(s);
a.foo.bar.baz();          // コンパイルは通る。実行時に落ちる ✗

// unknown … 「何か」だが、【使う前に絞り込みを強制される】★
let u: unknown = JSON.parse(s);
u.foo;                     // エラー
if (typeof u === 'object' && u !== null && 'foo' in u) { /* ここで使える */ }

any を使うと、そこから先の型チェックが全部無効になる
——これが「型があるのにバグる」典型的な原因である。
noImplicitAny: true で暗黙の any を禁止する。

既存JSのライブラリ資産の活用

型定義ファイル

型定義ファイルを集積しているサイト。

https://github.com/DefinitelyTyped/DefinitelyTyped

既存JSに型を後付けする

Moment.js に型を後付けする *.d.ts らしい。

https://gist.github.com/vvakame/c50ddbe213cfa758593c

※ このように、自作のライブラリにも
 型情報を与えることで TypeScript での利用が可能になる。

補足(型定義ファイルの現在): DefinitelyTyped の仕組みが
TypeScript 普及の決定打
だった。

【問題】 既存の JS ライブラリ(jQuery、lodash 等)には型がない
         → TypeScript から使うと all any になる

【解】  型定義ファイル(*.d.ts)を【別に書く】
         → 実装は JS のまま、型情報だけ後付けする ★
         → DefinitelyTyped に集約し、npm で配布
            npm install -D @types/jquery

現在の状況:

・新しいライブラリは【TypeScript で書かれている】ことが多い
   → 型定義が同梱される(@types が不要)
・古いライブラリは @types/xxx を入れる
・「型定義があるか」がライブラリ選定の基準の 1 つになった ★

確認方法:

# npm のページに TS のバッジがあるか、または
npm install -D @types/xxx   # ← 見つからなければ同梱されている可能性

移行メモ(原文のリンク先):

・DefinitelyTyped のリポジトリは
   borisyankov/DefinitelyTyped → 【DefinitelyTyped/DefinitelyTyped】に移った
   (上記では新しい URL に修正した)

・Moment.js は【メンテナンス モード】に入っており、
   公式が新規プロジェクトでの利用を推奨していない
   → 代替: date-fns、Day.js、Luxon、または
           【Temporal API】(ECMAScript 標準。実装が進行中)★

使い方

Visual Studio を使用しない場合。

インストール

  • npm
    npm(DNET_npm.md)を参考にする。

  • typescript

    npm install -g typescript

補足(-g(グローバル)は現在は非推奨): 原文は
グローバル インストールを示しているが、
現在はプロジェクト単位で入れるのが定石である。

# ✗ グローバル:マシン全体で 1 つの版になる
npm install -g typescript

# ○ プロジェクト単位(devDependencies)★
npm install -D typescript
npx tsc --version      # ← npx でプロジェクトの tsc を実行
【グローバルの問題】
   ・【プロジェクトごとに TypeScript の版が違う】のが普通
      → 版が違うとコンパイル結果や型エラーが変わる
   ・CI と開発者のマシンで版がずれる ★
   ・新メンバーの環境構築手順が増える

【プロジェクト単位なら】
   npm ci するだけで、全員・CI が【同じ版】になる

これは NuGet
PackageReference を使う理由と同じ
である
(依存をプロジェクトに閉じ込める)。

JavaScriptライブラリの取り込み

  • npm(DNET_npm.md)を使用する。

    npm install --save @types/jquery

移行メモ(--save ではなく -D: 型定義は
ビルド時にしか要らないため、
devDependencies-D / --save-dev)に入れるのが正しい。

npm install -D @types/jquery
【dependencies と devDependencies】
   dependencies    … 【実行時に必要】(React、axios 等)
   devDependencies … 【開発・ビルド時のみ】(TypeScript、@types/*、ESLint)

 → 分けておくと、本番の依存が小さくなる
 → 脆弱性スキャンの対象も絞れる

なお、--save は npm 5 以降は既定の動作であり、
書く必要がない(原文の時代には必要だった)。

設定(tsconfig.json)

tsconfig.json に、コンパイルの方法と対象の *.ts ファイルを設定する。

コンパイル

移行メモ(原文の誤記): 2 つ目の項目は原文で
「*.ts ファイルをビルコンパイル」となっていたため、
「コンパイル」と読み替えて記載した。

補足(現在は tsc でトランスパイルしないことが多い): 実務での
tsc の役割が変わった点を補っておく。

【原文の時代】
   tsc が【型チェック + JavaScript 生成】の両方を行う

【現在(Vite / esbuild / SWC 環境)】
   型チェック   … tsc --noEmit(型だけ見る。JS は出さない)★
   JS への変換  … esbuild / SWC(【型を無視して剥がすだけ】。桁違いに速い)

 → 役割を分けることで、開発サーバの起動が速くなった
// package.json
{ "scripts": {
    "dev": "vite",
    "build": "tsc --noEmit && vite build",   // ← 型チェックしてからビルド
    "typecheck": "tsc --noEmit --watch"
}}

重要な帰結:

・esbuild は【型エラーがあってもビルドが通る】
   → 型チェックを CI で必ず走らせないと、型の意味がなくなる ★
・エディタ(VS Code)は tsc の言語サービスで型を見ている
   → 手元では赤線が出るが、ビルドは通る、という状態があり得る

tsconfig.json の最低限の推奨設定:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,                 // ← これが最重要 ★
    "noUncheckedIndexedAccess": true,
    "noEmit": true,
    "skipLibCheck": true,           // 型定義の検査を省く(ビルドが速い)
    "esModuleInterop": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

strict: true は以下をまとめて有効にする

strictNullChecks、noImplicitAny、strictFunctionTypes、
strictBindCallApply、strictPropertyInitialization、
noImplicitThis、useUnknownInCatchVariables、alwaysStrict

 → 【新規は必ず true】。既存への導入は段階的に

Visual Studio を使用する場合。

JavaScriptライブラリの取り込み

  • NuGet を使用する。

    Install-Package jQuery
    Install-Package jquery.TypeScript.DefinitelyTyped

その他は自動的

  • Visual Studio プロジェクトに、*.ts の TypeScript ファイルを追加する。
  • (tsconfig.json の設定なども裏で行われている)
  • このファイルを保存すれば即座に JavaScript に変換され *.js ファイルに保存される。

移行メモ(NuGet で JS ライブラリを取る方式は廃れた): 原文が示す
NuGet 経由での JavaScript ライブラリ取得は、現在は行わない

【当時】 NuGet に jQuery、Bootstrap、@types 相当が置かれていた
         → .NET 開発者は NuGet だけ知っていればよかった

【問題】 ・npm 側の更新に追随しない(版が古い)
         ・npm のエコシステム(Tree Shaking、ESM)に乗れない
         ・NuGet パッケージの提供が止まった

【現在】 ・【npm を使う】(または LibMan)★
         ・Microsoft も NuGet での JS ライブラリ提供を停止した
手段 用途
npm / pnpm ビルドを伴う開発(SPA、TypeScript)★
LibMan ビルドなしで JS/CSS を配置したいだけ(従来の MVC/Razor Pages)
NuGet サーバ側の .NET ライブラリのみ

**「保存すれば即座に *.js に変換される」**という挙動も、
現在は既定ではない

・VS の「保存時にコンパイル」は無効が既定
・現在は Vite / webpack の watch が変換を担う
・[.esproj(JavaScript・TypeScriptプロジェクトシステム)] を使えば、
  npm run dev(Vite)が自動起動する ★

移行

  • コンパイルによって他の言語に移行可能

    tsc *.ts -t VERSION
    tsc *.ts --target VERSION
  • VERSION
    コンパイル出力の ECMAScript のバージョンを指定できる。

    • ES3 (default)
    • ES5
    • ES2015
    • ES2016
    • ES2017
    • ESNEXT

移行メモ(見出しと内容): 本節の「他の言語に移行可能」という表現は、
**正確には「出力する ECMAScript の版を選べる」**という意味である
(別言語に変換するわけではない)。

target の現況:

原文の時代 現在
既定 ES3 ES5(TS 5.0 以降)。ES3 は削除された
選択肢 ~ES2017 ES2015 ~ ES2024、ESNext
実務での選択 ES5(IE 対応) ES2020 ~ ES2022
【target を新しくする利点】
   ・出力される JS が【短く・読みやすく・速く】なる
      → 古い target ほど、ダウンレベル用の補助コードが増える
   ・async/await、class、optional chaining が【そのまま出る】

【古い target が必要だった理由】
   IE 11 対応 → 【IE は 2022 年にサポート終了】
             → 現在 ES5 に落とす理由はほぼない ★

targetlib は別物である点に注意する。

target … 【どの構文で出力するか】(async/await を変換するか等)
lib    … 【どの API の型定義を使うか】(Promise、Map、fetch の型)

 → target を上げても、実行環境が古ければ動かない
 → ブラウザ対応は【browserslist】と polyfill で別途管理する

参考

Qiita

slideshare

tsconfig.json

験なきものを思はずは

Microsoft Learn


Tags: 移行, プログラミング, ASP.NET, ASP.NET Web API, ASP.NET SPA, JavaScript

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally