この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:爽健
更新日時:2026-06-11 07:12:00

タイトル: 文法
SEOタイトル: TypeScript 基本文法完全ガイド

この記事の要点
  • 型注釈は let x: number = 1 のように変数名のあとにコロン + 型
  • interfacetype はほぼ同じ用途、interface は拡張可能、type は Union/Mapped Type 可能
  • Optional?、Nullable は | null
  • unknown は any より安全。型ガードで絞ってから使う
  • keyof / typeof / Conditional Type / Mapped Type で型レベルの高度な操作

変数宣言と型注釈

// let / const / var (var は非推奨)
let count: number = 0;
const PI: number = 3.14;
let name: string = "山田";
let active: boolean = true;

// 配列
let nums: number[] = [1, 2, 3];
let strs: Array<string> = ["a", "b"];

// タプル
let pair: [string, number] = ["age", 30];

// オブジェクト
let user: { name: string; age: number } = { name: "山田", age: 30 };

// 関数
let add: (a: number, b: number) => number = (a, b) => a + b;

関数の型

// 関数宣言
function greet(name: string, age?: number): string {
  return age ? `${name} (${age})` : name;
}

// アロー関数
const double = (x: number): number => x * 2;

// 戻り値型を推論させる
function double2(x: number) {
  return x * 2;   // : number と推論
}

// void / never
function log(msg: string): void {
  console.log(msg);
}
function fail(msg: string): never {
  throw new Error(msg);   // 戻ってこない
}

// オプショナル / デフォルト引数
function f(a: number, b?: number, c: number = 10) {}
// → b?: number means b: number | undefined

// Rest パラメータ
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0);
}

// 関数型を type で定義
type BinaryOp = (a: number, b: number) => number;
const mul: BinaryOp = (a, b) => a * b;

interface vs type

機能interfacetype
オブジェクト型定義
extends / implements△ (& で代替)
宣言マージ (重複定義)×
Union / Intersection×
Mapped / Conditional×
Primitive を別名化×
// interface (オブジェクト指向風)
interface User {
  id: number;
  name: string;
}
interface User { email: string; }  // ★ マージできる
interface Admin extends User { role: string; }

// type (関数型風、より柔軟)
type ID = string | number;          // ← interface ではできない
type Point = { x: number; y: number };
type Line = { start: Point; end: Point };

// Intersection
type Employee = User &amp; { salary: number };

// 大抵 type で OK。ライブラリ公開 API は interface 推奨 (拡張できるため)

Optional と Nullable

// Optional (プロパティ自体が無くても OK)
interface Config {
  host: string;
  port?: number;       // number | undefined
}

// Nullable (値が null になる可能性)
interface User {
  name: string;
  email: string | null;
}

// strictNullChecks 下では undefined と null は別物
let a: string = null;          // ❌ エラー
let b: string | null = null;   // ✅

// Optional chaining と Nullish coalescing
const user: User | undefined = getUser();
const len = user?.name?.length ?? 0;

Union / Intersection / Literal Types

// Union
type Status = &quot;active&quot; | &quot;inactive&quot; | &quot;pending&quot;;
let s: Status = &quot;active&quot;;    // ✅
let s2: Status = &quot;running&quot;;  // ❌

// Intersection
type A = { a: number };
type B = { b: string };
type AB = A &amp; B;            // { a: number; b: string }

// Numeric Literal
type Dice = 1 | 2 | 3 | 4 | 5 | 6;

// Template Literal Type (TS 4.1+)
type Greeting = `Hello, ${string}`;   // &quot;Hello, ...&quot; 形式
let g: Greeting = &quot;Hello, world&quot;;

unknown / any / never

意味使いどころ
any何でも入る (型チェック無効)移行期のみ、新規禁止
unknown何でも入るが使う前に型を絞る必要ありany の代わりに推奨
never絶対に発生しない型throw する関数、Exhaustive check
void戻り値がないこと関数の戻り値型
function parseJson(s: string): unknown {
  return JSON.parse(s);
}

const data = parseJson('{&quot;name&quot;:&quot;taro&quot;}');
// data.name;  // ❌ unknown なのでアクセス不可

// 型ガードで絞る
if (typeof data === &quot;object&quot; &amp;&amp; data !== null &amp;&amp; &quot;name&quot; in data) {
  console.log((data as { name: string }).name);
}

// 型述語関数
function isUser(x: unknown): x is User {
  return typeof x === &quot;object&quot; &amp;&amp; x !== null &amp;&amp; &quot;id&quot; in x;
}
if (isUser(data)) {
  data.id;  // ✅ User として扱える
}

as 型アサーション

// 開発者が「絶対この型」と保証する場合
const el = document.getElementById(&quot;app&quot;) as HTMLDivElement;

// const アサーション (リテラル型として固定)
const obj = { a: 1, b: 2 } as const;
// → { readonly a: 1; readonly b: 2 }

// 危険な多段アサーション (非推奨)
const x = (val as unknown) as number;

Generic (再掲)

function wrap<T>(value: T): { value: T } {
  return { value };
}
wrap<number>(1);     // { value: number }
wrap("hi");          // { value: string } と推論

// 制約付き Generic
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const user = { name: "taro", age: 30 };
getProp(user, "name");  // string
getProp(user, "xxx");   // ❌ "xxx" は keyof でない

Index Signature

// 任意のキー名で値を持つ
type Dict = { [key: string]: number };
const d: Dict = { a: 1, b: 2 };

// Record でも書ける
type Dict2 = Record<string, number>;

Mapped Type

type User = { id: number; name: string; email: string };

// 全部 readonly に
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type ReadOnlyUser = Readonly<User>;

// 全部 Optional に
type Partial<T> = { [K in keyof T]?: T[K] };
type PartialUser = Partial<User>;

// プロパティ名を変える (Key Remapping, TS 4.1+)
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
type UserGetters = Getters<User>;
// → { getId(): number; getName(): string; getEmail(): string }

keyof / typeof

// keyof: オブジェクト型のキー全部を Union で取得
type User = { id: number; name: string };
type UserKeys = keyof User;   // &quot;id&quot; | &quot;name&quot;

// typeof: 値から型を取得
const config = { host: &quot;localhost&quot;, port: 3000 };
type Config = typeof config;
// → { host: string; port: number }

// 組み合わせ
const colors = { red: &quot;#f00&quot;, green: &quot;#0f0&quot;, blue: &quot;#00f&quot; } as const;
type ColorName = keyof typeof colors;          // &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;
type ColorHex = typeof colors[ColorName];      // &quot;#f00&quot; | &quot;#0f0&quot; | &quot;#00f&quot;

Conditional Type

// 型レベルの if-else
type IsString<T> = T extends string ? true : false;
type A = IsString<"hi">;     // true
type B = IsString<42>;       // false

// 配列要素型を取り出す
type ElementType<T> = T extends (infer U)[] ? U : T;
type X = ElementType<number[]>;   // number
type Y = ElementType<string>;     // string (配列でなければそのまま)

// 関数の戻り値型を取り出す (組み込み ReturnType と同じ)
type ReturnTypeOf<T> = T extends (...args: any) => infer R ? R : never;

クラスの文法

class Animal {
  // public (省略可) / private / protected / readonly
  constructor(
    public readonly name: string,
    private age: number,
  ) {}

  greet(): string {
    return `${this.name} (${this.age})`;
  }

  // getter / setter
  get displayName() { return this.name.toUpperCase(); }
}

class Dog extends Animal {
  bark() { console.log(&quot;Woof&quot;); }
}

// 抽象クラス
abstract class Shape {
  abstract area(): number;
}
class Circle extends Shape {
  constructor(public r: number) { super(); }
  area() { return Math.PI * this.r ** 2; }
}

FAQ

Q: interface と type、新規はどっち?
A: 個人開発・チームコードは type、公開 API は interface が一般的。Airbnb スタイルガイド等は interface 推奨。

Q: 型情報を文字列に変換できる?
A: 不可。型はコンパイル時にしか存在しません。実行時の判定は typeof/instanceof/型述語関数で。

Q: as<Type> どっちが推奨?
A: as<Type>val 記法は JSX (.tsx) と競合するため非推奨です。