
TypeScriptの便利機能まとめ
Utility型とGenerics入門
TypeScriptの便利機能をまとめて解説。Partial・Pick・OmitなどのUtility型とGenericsの基本を初心者向けに紹介します。
全8回シリーズ — 目次
1 TypeScriptとは
2 環境構築
3 基本の型
4 関数と型
5 インターフェイス
6 クラス
7 実践的な型
8 便利機能まとめ
🎯 この記事のゴール
Utility Types・readonly・Generics・型の再利用テクニックを習得し、「実務で使える」状態になること。この回を終えれば、日常的なTypeScript開発で必要な型の知識は一通り揃います。 実行ファイルを用意しよう
今回用のファイルを作成します。Bunの場合はutility.ts 、Node.jsの場合はsrc/utility.ts です。
Bunの場合
touch utility.ts
bun --watch run utility.ts Node.js + npmの場合
touch src/utility.ts
npx tsc --watch # 別ターミナルで起動
node dist/utility.js Utility Types — 型を加工する組み込みツール群
TypeScript には型を変換・加工するための Utility Types が標準で用意されています。既存の型から「全部省略可能にした版」「一部だけ取り出した版」などを簡単に作れます。
Partial<T>
T のすべてのプロパティを 省略可能 にする。更新APIのリクエスト型に使いやすい。
Required<T>
T のすべてのプロパティを 必須 にする。Partial の逆。
Pick<T, K>
T から指定したプロパティ K だけを取り出す 。必要なフィールドだけの型を作る。
Omit<T, K>
T から指定したプロパティ K を 除外する 。id など自動生成フィールドを外すときに使う。
Record<K, V>
キーが K・値が V の オブジェクト型 を作る。辞書・マップ構造の型定義に便利。
Readonly<T>
T のすべてのプロパティを 変更不可 にする。不変なデータ構造を表現する。
NonNullable<T>
T から null と undefined を 除外する 。存在保証済みの値を扱う。
ReturnType<T>
関数型 T の 戻り値の型 を取り出す。既存関数の返り値型を再利用する。
Partial / Required — 全プロパティの省略可否を切り替える
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Partial: 全プロパティを省略可能にする(PATCHリクエストの型に最適)
type UpdateUserInput = Partial<User>;
// { id?: number; name?: string; email?: string; age?: number; }
function updateUser(id: number, input: UpdateUserInput): void {
console.log(`ユーザー${id}を更新:`, input);
}
// 一部だけ渡せる
updateUser(1, { name: "Alice Updated" });
updateUser(2, { email: "new@example.com", age: 30 });
// Required: 全プロパティを必須にする(デフォルト値補完後の型など)
interface Config {
host?: string;
port?: number;
debug?: boolean;
}
function resolveConfig(input: Config): Required<Config> {
return {
host: input.host ?? "localhost",
port: input.port ?? 3000,
debug: input.debug ?? false,
};
}
console.log(resolveConfig({ port: 8080 }));
// → { host: "localhost", port: 8080, debug: false } Bunの場合
bun run utility.ts
#ユーザー1を更新: { name: "Alice Updated" }
#ユーザー2を更新: { email: "new@example.com", age: 30 }
#{ host: "localhost", port: 8080, debug: false } Node.js + npmの場合
npx tsc && node dist/utility.js
#ユーザー1を更新: { name: 'Alice Updated' }
#ユーザー2を更新: { email: 'new@example.com', age: 30 }
#{ host: 'localhost', port: 8080, debug: false } Pick / Omit — プロパティを選別する
interface Article {
id: number;
title: string;
body: string;
authorId: number;
publishedAt: string | null;
createdAt: string;
}
// Pick: 必要なプロパティだけ取り出す(一覧表示用の軽量型)
type ArticleSummary = Pick<Article, "id" | "title" | "publishedAt">;
// { id: number; title: string; publishedAt: string | null }
// Omit: 不要なプロパティを除外する(POST リクエスト用:id/createdAt は自動生成)
type CreateArticleInput = Omit<Article, "id" | "createdAt">;
// { title: string; body: string; authorId: number; publishedAt: string | null }
const summary: ArticleSummary = {
id: 1,
title: "TypeScript入門",
publishedAt: "2025-04-01",
};
const newArticle: CreateArticleInput = {
title: "Bun入門",
body: "Bunとは高速なJSランタイムです",
authorId: 10,
publishedAt: null,
};
console.log(summary);
console.log(newArticle); Bunの場合
bun run utility.ts
#{ id: 1, title: "TypeScript入門", publishedAt: "2025-04-01" }
#{ title: "Bun入門", body: "Bunとは高速なJSランタイムです", authorId: 10, publishedAt: null } Node.js + npmの場合
npx tsc && node dist/utility.js
#{ id: 1, title: 'TypeScript入門', publishedAt: '2025-04-01' }
#{ title: 'Bun入門', body: 'Bunとは...', authorId: 10, publishedAt: null } Record — キーと値の型を指定したオブジェクト型
type Lang = "ja" | "en" | "zh";
// Record<キーの型, 値の型>
const messages: Record<Lang, string> = {
ja: "こんにちは",
en: "Hello",
zh: "你好",
};
// Lang のすべてのキーを網羅しないとエラーになる
console.log(messages.ja); // → こんにちは
console.log(messages.en); // → Hello
// IDをキーにしたキャッシュ構造にも使える
type UserCache = Record<number, { name: string; email: string }>;
const cache: UserCache = {
1: { name: "Alice", email: "alice@example.com" },
2: { name: "Bob", email: "bob@example.com" },
};
console.log(cache[1].name); // → Alice Bunの場合
bun run utility.ts
#こんにちは
#Hello
#Alice Node.js + npmの場合
npx tsc && node dist/utility.js
#こんにちは
#Hello
#Alice readonly — 変更を禁止して安全性を高める
// ① プロパティへの readonly
interface Config {
readonly apiUrl: string;
readonly version: string;
debug: boolean; // これだけ変更可能
}
const config: Config = {
apiUrl: "https://api.example.com",
version: "1.0.0",
debug: false,
};
config.debug = true; // OK
config.apiUrl = "..."; // エラー: readonly プロパティは変更不可
// ② readonly 配列(要素の追加・変更を禁止)
const ALLOWED_METHODS: readonly string[] = ["GET", "POST", "PUT", "DELETE"];
ALLOWED_METHODS.push("PATCH"); // エラー: readonly 配列には追加不可
// ③ Readonly<T> Utility Type(全プロパティを一括 readonly にする)
interface Point { x: number; y: number }
type FrozenPoint = Readonly<Point>;
const origin: FrozenPoint = { x: 0, y: 0 };
origin.x = 10; // エラー: x は readonly
console.log(config.apiUrl); // → https://api.example.com
console.log(origin); // → { x: 0, y: 0 }readonly をプロパティや配列に付けると、初期化後の変更をコンパイル時に禁止できます。意図しない書き換えを防ぎたいデータ構造に使います。
Bunの場合
bun run utility.ts
#https://api.example.com
#{ x: 0, y: 0 } Node.js + npmの場合
npx tsc && node dist/utility.js
#https://api.example.com
#{ x: 0, y: 0 } Generics(ジェネリクス)— 型を引数として渡す
ジェネリクスは「型をパラメータ化する」仕組みです。同じロジックをstring でもnumber でも使い回せる関数・クラスを書けます。any を使わずに型安全を保ったまま汎用化できるのが最大のメリットです。
// ① ジェネリクス関数 — T は「型の引数」
function identity<T>(value: T): T {
return value;
}
// 型引数は推論されるので省略できる
console.log(identity("hello")); // string として扱われる → hello
console.log(identity(42)); // number として扱われる → 42
// ② 配列の先頭要素を返す(T[] → T)
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
console.log(first([10, 20, 30])); // → 10(number 型)
console.log(first(["a", "b", "c"])); // → "a"(string 型)
// ③ 複数の型パラメータ
function pair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
console.log(pair("name", 42)); // → ["name", 42] 型は [string, number] Bunの場合
bun run utility.ts
#hello
#42
#10
#a
#[ "name", 42 ] Node.js + npmの場合
npx tsc && node dist/utility.js
#hello
#42
#10
#a
#[ 'name', 42 ] 制約付きジェネリクス — extends で型を絞る
T extends 型 と書くと、受け入れる型パラメータに制約を付けられます。「プロパティid を持つ型ならなんでも受け取れる」といった柔軟な汎用関数が作れます。
// id プロパティを持つ型に絞る
function findById<T extends { id: number }>(
items: T[],
id: number
): T | undefined {
return items.find((item) => item.id === id);
}
const users = [
{ id: 1, name: "Alice", role: "admin" },
{ id: 2, name: "Bob", role: "editor" },
];
const posts = [
{ id: 10, title: "TypeScript入門", authorId: 1 },
{ id: 11, title: "Bun入門", authorId: 2 },
];
// 同じ関数で User も Post も検索できる
console.log(findById(users, 1)); // → { id: 1, name: "Alice", role: "admin" }
console.log(findById(posts, 11)); // → { id: 11, title: "Bun入門", authorId: 2 } Bunの場合
bun run utility.ts
#{ id: 1, name: "Alice", role: "admin" }
#{ id: 11, title: "Bun入門", authorId: 2 } Node.js + npmの場合
npx tsc && node dist/utility.js
#{ id: 1, name: 'Alice', role: 'admin' }
#{ id: 11, title: 'Bun入門', authorId: 2 } 型の再利用テクニック
同じ型を何度も書き直さないためのパターンをまとめます。実務で「型のコピペ」が増えてきたと感じたら、これらのテクニックを使いましょう。
// ① keyof — オブジェクトのキーを Union 型として取り出す
interface User {
id: number; name: string; email: string;
}
type UserKey = keyof User; // "id" | "name" | "email"
// keyof と T[K] を組み合わせた汎用 getter
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { id: 1, name: "Alice", email: "alice@example.com" };
console.log(getProperty(user, "name")); // → Alice(string 型)
console.log(getProperty(user, "id")); // → 1(number 型)
// ② typeof — 変数から型を取り出す(型を二重管理しない)
const defaultConfig = {
host: "localhost",
port: 3000,
debug: false,
};
type AppConfig = typeof defaultConfig;
// { host: string; port: number; debug: boolean }
function startServer(config: Partial<AppConfig> = {}): void {
const merged = { ...defaultConfig, ...config };
console.log(`起動: ${merged.host}:${merged.port} debug=${merged.debug}`);
}
startServer(); // → 起動: localhost:3000 debug=false
startServer({ port: 8080, debug: true }); // → 起動: localhost:8080 debug=true
// ③ Parameters — 関数の引数型を取り出す
function createPost(title: string, body: string, authorId: number) {
return { title, body, authorId };
}
type CreatePostArgs = Parameters<typeof createPost>;
// [title: string, body: string, authorId: number]
const args: CreatePostArgs = ["TypeScript Tips", "本文...", 1];
console.log(createPost(...args)); Bunの場合
bun run utility.ts
#Alice
#1
#起動: localhost:3000 debug=false
#起動: localhost:8080 debug=true
#{ title: "TypeScript Tips", body: "本文...", authorId: 1 } Node.js + npmの場合
npx tsc && node dist/utility.js
#Alice
#1
#起動: localhost:3000 debug=false
#起動: localhost:8080 debug=true
#{ title: 'TypeScript Tips', body: '本文...', authorId: 1 } シリーズ総まとめ早見表
全8回で学んだ機能を一枚の表にまとめました。迷ったときの参照用に保存しておいてください。
| 機能 | 書き方 | 用途 |
|---|---|---|
| 基本型 | string / number / boolean | 変数・引数・戻り値の型注釈 |
| 配列 | T[] / Array<T> | 要素の型を指定した配列 |
| オブジェクト | { key: T } | インラインのオブジェクト型注釈 |
| interface | interface Foo { ... } | オブジェクト形状の名前付き定義・継承 |
| type | type Foo = ... | Union・Literal・プリミティブ別名 |
| Union型 | A | B | 複数の型を取り得る値 |
| Literal型 | "draft" | "published" | 取り得る値を列挙で限定 |
| 型ガード | typeof / in / is | Union型の実行時絞り込み |
| readonly | readonly x: T | 変更不可プロパティ・配列 |
| Generics | <T> | 型を引数化した汎用関数・クラス |
| Partial<T> | Partial<User> | 全プロパティを省略可能に |
| Required<T> | Required<Config> | 全プロパティを必須に |
| Pick<T,K> | Pick<User,"id"|"name"> | 指定プロパティだけ抽出 |
| Omit<T,K> | Omit<User,"id"> | 指定プロパティを除外 |
| Record<K,V> | Record<Lang,string> | キーと値の型を指定したオブジェクト |
| keyof | keyof User | オブジェクトのキー名をUnion型で取得 |
| typeof | typeof obj | 変数から型を取り出す |
| ReturnType | ReturnType<typeof fn> | 関数の戻り値型を取得 |
| 基本型 Parameters | Parameters<typeof fn> | 変数・引数・戻り値の型注釈 関数の引数型をタプルで取得 |
🎉
全8回シリーズ、お疲れさまでした!
TypeScriptの基礎から実務レベルの型テクニックまで、一通り学び終えました。
ここからは実際にプロジェクトで書きながら身につけていきましょう。
✅ シリーズ完走おめでとうございます
型を書くことが「面倒な作業」から「バグを防ぐ頼もしい仕組み」に感じられるようになったら、TypeScript を本当に理解している証拠です。ここからは書く量を増やすだけ。実務の中で型と仲良くなっていきましょう!