TypeScript型リファレンス - 基本型からユーティリティ型・高度な型操作まで

TypeScriptの型システムに関するリファレンス。基本型からユーティリティ型、高度な型操作まで、実用的なコード例とともに掲載している。

基本型(Primitive Types)

説明
string文字列'hello', "world", `template`
number数値(整数・浮動小数点)42, 3.14, 0xFF, 1e10
boolean真偽値true, false
null値が存在しないことを明示null
undefined値が未定義undefined
bigint任意精度の整数100n, BigInt(100)
symbol一意の識別子Symbol('id')
const name: string = 'TypeScript'
const age: number = 10
const active: boolean = true
const nothing: null = null
const notDefined: undefined = undefined
const big: bigint = 9007199254740991n
const id: symbol = Symbol('id')

特殊な型

説明用途
any型チェックを無効化移行期のコード、型定義が困難な場合
unknown型安全なany外部入力の受け取り
never到達不能な値例外スロー、網羅性チェック
void戻り値なし戻り値のない関数
object非プリミティブ型オブジェクト全般
// any: 何でも代入でき、何にでも代入できる(型安全性なし)
let anything: any = 'hello'
anything = 42
anything.nonExistentMethod() // エラーにならない

// unknown: 何でも代入できるが、使用時に型チェックが必要
let input: unknown = 'hello'
// input.toUpperCase()  // エラー: unknown型のまま操作不可
if (typeof input === 'string') {
  input.toUpperCase()   // OK: 型を絞り込んでから操作
}

// never: 正常に終了しない関数の戻り値
function throwError(message: string): never {
  throw new Error(message)
}

// void: 戻り値のない関数
function log(message: string): void {
  console.log(message)
}

any vs unknown

特性anyunknown
任意の値を代入
他の型に代入不可(型チェック必要)
プロパティアクセス不可(型チェック必要)
型安全性なしあり

リテラル型(Literal Types)

特定の値のみを許容する型。constで宣言した変数は自動的にリテラル型になる。

// 文字列リテラル型
type Direction = 'north' | 'south' | 'east' | 'west'
const dir: Direction = 'north' // OK
// const dir2: Direction = 'up' // エラー

// 数値リテラル型
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6

// booleanリテラル型
type True = true

// const アサーション(as const)
const config = {
  endpoint: 'https://api.example.com',
  retries: 3,
} as const
// 型: { readonly endpoint: "https://api.example.com"; readonly retries: 3 }

ユニオン型とインターセクション型

ユニオン型(Union Types)

複数の型のいずれかを表す。| で結合する。

type StringOrNumber = string | number

function format(value: StringOrNumber): string {
  if (typeof value === 'string') {
    return value.toUpperCase()
  }
  return value.toFixed(2)
}

// 判別共用体(Discriminated Union)
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2
    case 'rectangle':
      return shape.width * shape.height
  }
}

インターセクション型(Intersection Types)

複数の型をすべて満たす型。& で結合する。

type HasName = { name: string }
type HasAge = { age: number }
type Person = HasName & HasAge

const person: Person = { name: 'Alice', age: 30 } // 両方のプロパティが必須

型エイリアス(type)とインターフェース(interface)

比較表

機能typeinterface
オブジェクト型
ユニオン型不可
インターセクション型可(&可(extends
宣言のマージ不可
Mapped Types不可
プリミティブのエイリアス不可
クラスのimplements
// type: ユニオン型やプリミティブのエイリアスが可能
type ID = string | number
type Status = 'active' | 'inactive'

type UserType = {
  id: ID
  name: string
  status: Status
}

// interface: 宣言のマージが可能(同名で再宣言すると統合される)
interface UserInterface {
  id: string
  name: string
}

interface UserInterface {
  email: string // 既存の定義に追加される
}
// UserInterface = { id: string; name: string; email: string }

// interface: extends による継承
interface Employee extends UserInterface {
  department: string
}

使い分けの指針: オブジェクトの形状定義にはinterface、ユニオン型や型の組み合わせにはtypeを使うのが一般的。

配列・タプル

// 配列
const numbers: number[] = [1, 2, 3]
const strings: Array<string> = ['a', 'b', 'c'] // ジェネリクス記法
const mixed: (string | number)[] = [1, 'two', 3]

// 読み取り専用配列
const readonlyArr: readonly number[] = [1, 2, 3]
const readonlyArr2: ReadonlyArray<number> = [1, 2, 3]

// タプル: 固定長・各要素の型が決まった配列
const tuple: [string, number] = ['hello', 42]
const namedTuple: [name: string, age: number] = ['Alice', 30] // ラベル付き

// 可変長タプル
type StringNumberPairs = [string, ...number[]]
const pairs: StringNumberPairs = ['sum', 1, 2, 3]

ジェネリクス(Generics)

型をパラメータ化して再利用可能にする仕組み。

// ジェネリック関数
function identity<T>(value: T): T {
  return value
}
const str = identity('hello') // 型推論: string
const num = identity<number>(42) // 明示的に指定

// 複数の型パラメータ
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second]
}

// ジェネリック型
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E }

// ジェネリックインターフェース
interface Repository<T> {
  findById(id: string): T | undefined
  findAll(): T[]
  save(entity: T): void
}

// ジェネリッククラス
class Stack<T> {
  private items: T[] = []
  push(item: T): void {
    this.items.push(item)
  }
  pop(): T | undefined {
    return this.items.pop()
  }
}

ジェネリック制約(extends

// T は { length: number } を持つ型に制限
function logLength<T extends { length: number }>(value: T): void {
  console.log(value.length)
}
logLength('hello')    // OK: stringはlengthを持つ
logLength([1, 2, 3])  // OK: 配列はlengthを持つ
// logLength(42)      // エラー: numberにlengthはない

// keyof 制約
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}
const user = { name: 'Alice', age: 30 }
getProperty(user, 'name') // OK: 戻り値型は string
// getProperty(user, 'email') // エラー: 'email' は keyof typeof user にない

ユーティリティ型(Utility Types)

TypeScript組み込みの型変換ユーティリティ。

オブジェクト操作系

interface User {
  id: number
  name: string
  email: string
  age: number
}

// Partial<T>: すべてのプロパティをオプショナルに
type PartialUser = Partial<User>
// { id?: number; name?: string; email?: string; age?: number }

// Required<T>: すべてのプロパティを必須に
type RequiredUser = Required<Partial<User>>
// { id: number; name: string; email: string; age: number }

// Readonly<T>: すべてのプロパティを読み取り専用に
type ReadonlyUser = Readonly<User>
// { readonly id: number; readonly name: string; ... }

// Pick<T, K>: 指定したプロパティだけ抽出
type UserSummary = Pick<User, 'id' | 'name'>
// { id: number; name: string }

// Omit<T, K>: 指定したプロパティを除外
type UserWithoutEmail = Omit<User, 'email'>
// { id: number; name: string; age: number }

// Record<K, V>: キーと値の型を指定してオブジェクト型を作成
type UserRoles = Record<string, 'admin' | 'user' | 'guest'>
// { [key: string]: 'admin' | 'user' | 'guest' }

ユニオン操作系

type Status = 'active' | 'inactive' | 'pending' | 'deleted'

// Exclude<T, U>: T から U に該当する型を除外
type ActiveStatus = Exclude<Status, 'deleted'>
// 'active' | 'inactive' | 'pending'

// Extract<T, U>: T から U に該当する型だけ抽出
type NonActiveStatus = Extract<Status, 'inactive' | 'deleted'>
// 'inactive' | 'deleted'

// NonNullable<T>: null と undefined を除外
type MaybeString = string | null | undefined
type DefiniteString = NonNullable<MaybeString>
// string

関数操作系

function createUser(name: string, age: number): User {
  return { id: Date.now(), name, email: '', age }
}

// ReturnType<T>: 関数の戻り値の型を取得
type CreatedUser = ReturnType<typeof createUser>
// User

// Parameters<T>: 関数のパラメータの型をタプルで取得
type CreateUserParams = Parameters<typeof createUser>
// [name: string, age: number]

// Awaited<T>: Promiseをアンラップした型を取得
type ResolvedValue = Awaited<Promise<string>>
// string

type DeepResolved = Awaited<Promise<Promise<number>>>
// number

文字列操作系

type Upper = Uppercase<'hello'>       // 'HELLO'
type Lower = Lowercase<'HELLO'>       // 'hello'
type Cap = Capitalize<'hello'>        // 'Hello'
type Uncap = Uncapitalize<'Hello'>    // 'hello'

型ガード(Type Guards)

実行時に型を絞り込む仕組み。

typeof

function process(value: string | number) {
  if (typeof value === 'string') {
    // ここでは value: string
    return value.toUpperCase()
  }
  // ここでは value: number
  return value * 2
}

instanceof

class Dog {
  bark() { return 'Woof!' }
}
class Cat {
  meow() { return 'Meow!' }
}

function speak(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    return animal.bark()
  }
  return animal.meow()
}

in 演算子

type Fish = { swim: () => void }
type Bird = { fly: () => void }

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim()
  } else {
    animal.fly()
  }
}

ユーザー定義型ガード(is

is キーワードで戻り値の型を型述語(type predicate)として指定する。

interface Admin {
  role: 'admin'
  permissions: string[]
}
interface Guest {
  role: 'guest'
}

function isAdmin(user: Admin | Guest): user is Admin {
  return user.role === 'admin'
}

function showDashboard(user: Admin | Guest) {
  if (isAdmin(user)) {
    // user: Admin として扱える
    console.log(user.permissions)
  }
}

satisfies 演算子

型の制約を検証しつつ、推論された型を保持する(TypeScript 4.9+)。

type Colors = Record<string, [number, number, number] | string>

const palette = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} satisfies Colors

// 推論された型が保持される
palette.red.map((v) => v * 2) // OK: [number, number, number] と推論
palette.green.toUpperCase()   // OK: string と推論

Mapped Types

既存の型を元に新しい型を生成する。

// 基本形: すべてのプロパティを変換
type Nullable<T> = {
  [K in keyof T]: T[K] | null
}

interface Config {
  host: string
  port: number
  debug: boolean
}

type NullableConfig = Nullable<Config>
// { host: string | null; port: number | null; debug: boolean | null }

// 修飾子の追加・削除
type Mutable<T> = {
  -readonly [K in keyof T]: T[K]  // readonly を除去
}

type Optional<T> = {
  [K in keyof T]+?: T[K]  // オプショナルを追加
}

// Key Remapping(as句)
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}

type ConfigGetters = Getters<Config>
// { getHost: () => string; getPort: () => number; getDebug: () => boolean }

// 特定のプロパティを除外するMapping
type OmitByType<T, U> = {
  [K in keyof T as T[K] extends U ? never : K]: T[K]
}

type WithoutBooleans = OmitByType<Config, boolean>
// { host: string; port: number }

Conditional Types

extends キーワードを用いた条件分岐で型を決定する。

// 基本形: T extends U ? X : Y
type IsString<T> = T extends string ? true : false

type A = IsString<'hello'> // true
type B = IsString<42>      // false

// ユニオン型に対する分配(Distributive Conditional Types)
type ToArray<T> = T extends unknown ? T[] : never
type Result = ToArray<string | number>
// string[] | number[](分配されてそれぞれに適用される)

// 分配を防ぐにはタプルで囲む
type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never
type Result2 = ToArrayNonDist<string | number>
// (string | number)[]

// infer: 条件型の中で型を推論・キャプチャ
type ElementType<T> = T extends (infer U)[] ? U : T
type E1 = ElementType<string[]>  // string
type E2 = ElementType<number>    // number

// 関数の戻り値型を取得(ReturnType の実装)
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never

// Promise の中身を再帰的に取得
type DeepAwaited<T> = T extends Promise<infer U> ? DeepAwaited<U> : T
type D = DeepAwaited<Promise<Promise<string>>> // string

Template Literal Types

文字列リテラル型をテンプレートで組み合わせる。

// 基本形
type Greeting = `Hello, ${string}`
const greet: Greeting = 'Hello, World' // OK

// ユニオン型の組み合わせ
type Vertical = 'top' | 'bottom'
type Horizontal = 'left' | 'right'
type Position = `${Vertical}-${Horizontal}`
// 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'

// イベントハンドラの型
type EventName = 'click' | 'focus' | 'blur'
type EventHandler = `on${Capitalize<EventName>}`
// 'onClick' | 'onFocus' | 'onBlur'

// パターンマッチング
type ExtractRouteParams<T extends string> =
  T extends `${string}:${infer Param}/${infer Rest}`
    ? Param | ExtractRouteParams<Rest>
    : T extends `${string}:${infer Param}`
      ? Param
      : never

type Params = ExtractRouteParams<'/users/:userId/posts/:postId'>
// 'userId' | 'postId'

インデックス型

// インデックスシグネチャ
interface StringMap {
  [key: string]: string
}

// インデックスアクセス型(Indexed Access Types)
interface User {
  id: number
  name: string
  address: {
    city: string
    zip: string
  }
}

type UserName = User['name']           // string
type City = User['address']['city']    // string
type IdOrName = User['id' | 'name']   // number | string

// 配列要素の型を取得
const roles = ['admin', 'editor', 'viewer'] as const
type Role = (typeof roles)[number]  // 'admin' | 'editor' | 'viewer'

keyof と typeof

// keyof: オブジェクト型のキーをユニオン型で取得
interface User {
  id: number
  name: string
  email: string
}
type UserKeys = keyof User // 'id' | 'name' | 'email'

// typeof: 値から型を取得
const config = {
  api: 'https://api.example.com',
  timeout: 5000,
  retries: 3,
}
type Config = typeof config
// { api: string; timeout: number; retries: number }

// keyof typeof: オブジェクト値のキーをユニオン型で取得
type ConfigKeys = keyof typeof config // 'api' | 'timeout' | 'retries'

// const アサーションとの組み合わせ
const STATUS = {
  Active: 'ACTIVE',
  Inactive: 'INACTIVE',
} as const

type StatusValues = (typeof STATUS)[keyof typeof STATUS]
// 'ACTIVE' | 'INACTIVE'

型アサーション

// as 構文
const input = document.getElementById('name') as HTMLInputElement
input.value = 'hello'

// 非nullアサーション(!)
function getElement(id: string) {
  const el = document.getElementById(id)!  // null でないと断言
  return el
}

// const アサーション
const arr = [1, 2, 3] as const     // readonly [1, 2, 3]
const obj = { x: 10 } as const    // { readonly x: 10 }

関数型

// 関数型の定義
type Callback = (error: Error | null, data: string) => void
type AsyncFn = () => Promise<void>

// オーバーロード
function parse(input: string): number
function parse(input: number): string
function parse(input: string | number): number | string {
  if (typeof input === 'string') return parseInt(input, 10)
  return input.toString()
}

// ジェネリック関数型
type MapFn<T, U> = (item: T, index: number) => U

// コンストラクタ型
type Constructor<T> = new (...args: any[]) => T

宣言ファイル(.d.ts)でよく使う構文

// 型のみのインポート・エクスポート
import type { User } from './types'
export type { User }

// declare: 外部で定義された値の型を宣言
declare const API_URL: string
declare function fetchData(url: string): Promise<unknown>

// declare module: モジュールの型を拡張
declare module '*.css' {
  const classes: Record<string, string>
  export default classes
}

// グローバル型の拡張
declare global {
  interface Window {
    analytics: {
      track(event: string): void
    }
  }
}

参考リンク