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
| 特性 | any | unknown |
|---|---|---|
| 任意の値を代入 | 可 | 可 |
| 他の型に代入 | 可 | 不可(型チェック必要) |
| プロパティアクセス | 可 | 不可(型チェック必要) |
| 型安全性 | なし | あり |
リテラル型(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)
比較表
| 機能 | type | interface |
|---|---|---|
| オブジェクト型 | 可 | 可 |
| ユニオン型 | 可 | 不可 |
| インターセクション型 | 可(&) | 可(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
}
}
}
参考リンク
- TypeScript Handbook - 公式ハンドブック
- TypeScript Cheat Sheets - 公式チートシート
- Utility Types - TypeScript - ユーティリティ型の公式リファレンス
- TypeScript Deep Dive - 型システムの詳細解説
- Type Challenges - 型レベルプログラミングの練習問題集