l

o

a

d

i

n

g

.

.

.

TypeScriptを自分流環境で構築して学習する話 #1 型システムのクセを理解する手順

2026/01/09

Javascript プログラミング 学習

t f B! P L
TS(TypeScript)は、何といってもJavascriptの課題とも言える、型を補うために作られたライブラリと言っても過言ではないでしょう。 コンパイル言語を扱ってきたプログラマが、Javascrtiptを使ってまず思うのが、型宣言が無くて不安な気持ちに駆られてしまうという、物足りなさの心境は、色々な人からよく聞きました。 Web系のインタプリタ系言語をプログラミング学習で最初からやってきた人にとっては、この感覚が何となくわかりにくいのですが、 型宣言や、コンパイルするのは、心の安心感が得られるというメリットがあります。 Javascriptは、実際にブラウザでページを表示して初めてエラーが確認できるため、本番アップ後にエラーが確認されるというケースも頻繁に発生してしまいます。 でも、本番アップ前にコンパイルすると、少なくてもその時点でエラーが見つかり、事なきを得たという救済事態に救われたエンジニアも数多くいるでしょう。 そんな人は、型宣言が甘いJavascriptには、物足りなさを感じて仕方がないのです。 TSは、Javascript言語をコンパイル言語と同レベルでの型宣言が必要になる言語に発展させたため、今現在人気も向上しているのがうなづけます。 ということで、TS学習のまず最初は「型」について理解していきたいと思います。

型の宣言

Javascriptの変数定義の処理は以下のように書きます。 var a = 1 let b = "test" const arr = [1,2,3] これに対して、TSは、以下のように書きます。 let a: number = 1 let b: string = "test" const arr: number[] = [1,2,3] ざっくりと、宣言一覧をまとめると次のリストの通り。 // ========================== // 基本プリミティブ型 // ========================== // 数値 const a: number = 1; // 任意精度整数 const b: bigint = 10n; // 文字列 let c: string = "test"; // 真偽値 const bool: boolean = true; // Null const n: null = null; // Undefined const u: undefined = undefined; // シンボル(ユニーク識別子) const sym: symbol = Symbol("id"); // ========================== // 特殊型(JavaScriptには無い) // ========================== // なんでもOK(型チェック無効) const x: any = "自由"; // 型は「判明していない」が操作は禁止 → unknownは安全なany let y: unknown = "test"; // 値が存在しない(never戻り値の関数や到達不可) function fail(): never { throw new Error("Error"); } // ========================== // 配列 // ========================== const nums: number[] = [1, 2, 3]; const vals: Array<string> = ["a", "b", "c"]; // Generic記法 // readonly配列(変更禁止) const frozen: readonly number[] = [1, 2, 3]; // タプル(固定長配列・要素型が固定) const tuple: [number, string, boolean] = [1, "a", true]; // ========================== // オブジェクト / 型リテラル // ========================== const obj: { a: number; b: string } = { a: 1, b: "a" }; // ? = Optional(存在してもしなくても良い) const obj2: { a: number; b?: string } = { a: 1 }; // レコード型(キー型と値型を定義) const users: Record<string, number> = { taro: 20, jiro: 30, }; // ========================== // 関数型 // ========================== // 返り値なし(意図として「戻り値は使うな」) function hello(): void { console.log("hello"); } // 引数と戻り値の型指定 function add(a: number, b: number): number { return a + b; } // アロー関数型 const fn: (name: string) => string = (name) => `Hello ${name}`; // ========================== // ユニオン型 / リテラル型 // ========================== // 値の候補を型制約 let mode: "on" | "off" = "on"; // 型の OR let input: string | number = 10; // 型の AND type A = { a: number }; type B = { b: string }; type C = A & B; // {a:number, b:string} // ========================== // Enum(列挙型) // ========================== enum Direction { Up, Down, Left, Right, } const d: Direction = Direction.Up;

any の本質

どんな値でも入り、どんな操作も許可されるのがany。 型安全が崩壊し、コンパイラが見守り放棄するモード。 JSからTSに移行する時の移行用バッファ扱いが正解になる。

unknown の役割

受け皿としては any と同じく「何でも入る」型。 ただし操作できない=「安全な曖昧」と考えた方がいい。あまり使わないけどね。 扱うには typeof や型ガードが必要 → 型を正しく絞る流れを強制する必要がある。

never の意味

「到達しない・存在し得ない値」という意味。 例:throw・while(true)・switch exhaustiveness check 型の欠落ではなく 矛盾が検出された証拠。

void の役割

「値を返すが受け取らなくていい関数」という意図を示す型。 undefined と似ているが、設計意図(戻り値を使わせたくない)が含まれるのでちゃんと理解して扱いましょう。

Union型 (A | B) の捉え方

「どちらか」ではなく「まだ確定してない型の候補リスト」。 使用前に narrowing(絞り込み)するのが前提だと理解しましょう。 サーバーレスポンスやフォーム入力と相性が良い。

Intersection型 (A & B) の本質

両方の契約を満たす型。 実体は「型の合成」であり、継承やmixin設計と親和性が高い。

Literal型の意味

"ON" | "OFF" のように「値を固定して表現する」型。 Enumより柔軟で型安全なフラグ設計が可能です。 「値自体が型になる」世界がここで見える。

型を宣言するか否かと書くべきタイミングについて

型を書くべきタイミング

1. 外部から値が入ってくる境界レイヤー APIレスポンス、フォーム入力、LocalStorage、DB、URL検索パラメータなど → 型が無いと推論不能・エラー原因が非同期で爆発する 2. 公開する関数・ライブラリの引数と戻り値 "使う側" が推論ではなく意図を理解できる状態にするため 3. 意図的な制約やパターンを保証したい時 Union / Literal / Enum / Tuple など → JavaScriptには存在しない「ルール」をシステム化する場面 4. クラスやインターフェースで構造を定義する時 モデリングやデータ設計が絡む場所は曖昧にしないほうがいい

型を書かないほうがいいケース

1. 代入時に型が明らかで、変更意図がないローカル変数 const count = 1; // number で十分 const name = "user"; // string で自動推論 2. 一時的・処理内部だけで使う変数 関数内部の値は推論に任せたほうが読みやすくなる 3. map / filter / reduce の中でTSが推論できている場合 const ids = users.map(u => u.id); // 推論OKなら型書かない 4. 型を重複して書いてしまうケース(DRY違反) type User = { id: number, name: string }; // 悪い例(重複) const u: { id: number; name: string } = { id: 1, name: "a" }; // 良い例 const u: User = { id: 1, name: "a" };

型を書くべきか迷ったときの判断基準

1. その変数・関数は外の世界と繋がる? → Yes → 書く → No → 推論に任せる 2. 読んだ人(未来の自分)がすぐ意図を理解できる? → No → 書く → Yes → 書かなくてOK 3. 型がバグ予防や可読性向上に貢献する? → Yes → 書く → No → 書かない

あとがき

型は「データではなくルール」という事を理解しましょう。
値は、ランタイムに存在するもの。 型は、コンパイル時に存在するもの。
型は、JSコードを説明する文章であり、制御装置でもある。 TSの目的は「コードの未来のバグを、コンパイル時点で潰す」という風に考えてもいいかも。 とりあえず、型宣言を覚えるだけで、TSを使う意義はありますので、内容をちゃんと覚えておくのがいいでしょう。 自分で書けることも重要ですが、他人が書いたTSコードを問題なく、読めるようになることも重要ですよ。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ