この記事の前提
JavaScriptは書けるがTypeScriptは触ったことがない人向け。「型」とは何か、なぜ必要なのか、JSとの具体的な差分を解説する。
なぜTypeScriptが必要なのか
JavaScriptでは以下のコードが実行時に初めてエラーになる:
// JavaScript — 実行するまでバグに気づけない
function greet(user) {
return "Hello, " + user.name.toUpperCase();
}
greet(null); // TypeError: Cannot read properties of null
TypeScriptなら、コードを書いた瞬間にエディタが警告する:
// TypeScript — 書いた瞬間にエラーが出る
function greet(user: { name: string }) {
return "Hello, " + user.name.toUpperCase();
}
greet(null); // コンパイルエラー: 'null'は引数の型に割り当てられない
型はバグ防止策でありドキュメントでもある。
基本の型注釈
const name: string = "田中";
const age: number = 28;
const scores: number[] = [80, 90, 70];
interface — オブジェクトの型に名前を付ける
interface User {
id: number;
name: string;
email: string;
age?: number; // ? で省略可能
}
// OK
const u: User = { id: 1, name: "田中", email: "tanaka@example.com" };
// コンパイルエラー: emailが足りない
const bad: User = { id: 1, name: "田中" };
union型 — 「AまたはB」を表現する
// string か number のどちらかを受け取る
function formatId(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase();
}
return String(id);
}
formatId("abc"); // "ABC"
formatId(123); // "123"
typeofでチェックすると、その分岐内ではTypeScriptが型を絞り込んでくれる(型の絞り込み = narrowing)。
generics — 型を引数にする
// T は「何の型が来るか分からないが、入力と出力で一貫させる」という宣言
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // number | undefined
const s = first(["a", "b"]); // string | undefined
genericsは「型の変数」だと考えれば理解しやすい。
satisfies — 型チェックしつつ推論も活かす(TS 4.9+)
type Color = "red" | "green" | "blue";
const palette = {
primary: "red",
secondary: "green",
} satisfies Record<string, Color>;
// palette.primary の型は "red"(Colorではなくリテラル型が保持される)
推奨 tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist"
},
"include": ["src/**/*"]
}
"strict": trueは必ず有効にする。これを切ると型チェックが甘くなり、TSを使う意味が半減する。
JSでバグになるコードがTSで止まる例
// 1. プロパティ名のtypo
interface Config { timeout: number; }
const cfg: Config = { timout: 100 }; // コンパイルエラー: timout は存在しない
// 2. 戻り値の型の不一致
function getAge(): number {
return "25"; // コンパイルエラー: string を number に割り当てられない
}
// 3. switch文の網羅性チェック
type Status = "active" | "inactive" | "pending";
function getMessage(s: Status): string {
switch (s) {
case "active": return "有効";
case "inactive": return "無効";
// "pending" を書き忘れるとコンパイルエラー
}
}
まとめ
TypeScriptのコアは「型注釈 → interface → union → generics」の4段階。strict: trueを有効にして、エディタの赤線に従えばいい。