はじめに|この記事で得られる価値
「定数オブジェクトを更新するたびに、型定義も手動で直す…正直、これって無駄じゃないですか?」
私たちフロントエンドエンジニアがReactやNext.jsで開発していると、型定義の二重管理にモヤモヤする瞬間がよくあります。
特にプロジェクトが大きくなるほど、修正漏れによるコンパイルエラーや実行時バグのリスクが高まります。
「DRY原則(Don’t Repeat Yourself)」を重視する現場エンジニアにとって、同じ情報を2箇所に書く手間とリスクは見過ごせません。
でも、TypeScriptにはこの“泥臭い作業”を一掃する魔法の1行が用意されています。それがkeyof typeofです。
(TypeScriptの基礎や導入方法については『TypeScriptの始め方|Node.jsとVSCodeで学ぶ開発環境構築ガイド【初心者向け完全解説】』をご参照ください)
1. 型定義の二重管理、なぜ苦しい?“keyof typeof”で1箇所管理へ
「信頼できる情報源(Single Source of Truth)」を作るのはプログラミングの鉄則。でも、TypeScript現場ではこんな二重管理が散見されます。
- const STATUS = { … }で値を定義
- type Status = ‘pending’ | ‘active’ | ‘deleted’で型を手動定義
この運用だと、オブジェクトに新しいステータスを追加するたびに型定義もセットで更新が必要。人間が手動でやる以上、修正漏れは必ず発生します。
keyof typeofを導入すれば、修正箇所は「2箇所」→「1箇所」に。オブジェクトを更新すれば型も自動で追従。これが保守性の高いコードの鍵です。
2. “typeof”と“keyof”の正体を図解で理解
■ typeof:値の構造を型に変換
- JavaScriptのtypeof(実行時):型名(”string”など)を返す
- TypeScriptのtypeof(コンパイル時):値の構造を型として抽出
const colors = {
primary: '#007bff',
secondary: '#6c757d'
};
type ColorsType = typeof colors;
// { primary: string; secondary: string; }
(TypeScriptとJavaScriptの違いについては『TypeScriptとは?JavaScriptとの違いを初心者向けにわかりやすく解説』をご参照ください)
用語解説:TypeScript
JavaScriptに型安全性を加えた言語。型定義や型推論によって、バグの早期発見や保守性向上を実現する。用語解説:typeof
JavaScriptでは実行時に型名(”string”など)を返す演算子。TypeScriptでは変数やオブジェクトの型情報を抽出する型演算子として使われる。用語解説:keyof
オブジェクト型のプロパティ名(キー)をUnion型として抽出するTypeScriptの型演算子。用語解説:Union型
複数の型をまとめて「どれか一つ」として扱う型。例:‘A’ | ‘B’ | ‘C’。
■ keyof:キーをUnion型で抽出
type User = { id: number; name: string; };
type UserKey = keyof User; // 'id' | 'name'
この2つを組み合わせることで、変数の実体からキー一覧を型として取り出せます。
3. 【実践】“keyof typeof”で型定義を自動化する魔法の1行
■ Before:手動で型を管理
const USER_STATUS = {
PENDING: 1,
ACTIVE: 2,
DELETED: 9,
} as const;
type UserStatusKey = 'PENDING' | 'ACTIVE' | 'DELETED';
■ After:自動で型を抽出
const USER_STATUS = {
PENDING: 1,
ACTIVE: 2,
DELETED: 9,
} as const;
type UserStatusKey = keyof typeof USER_STATUS; // 'PENDING' | 'ACTIVE' | 'DELETED'
■ as constが必須な理由
const WITHOUT_AS_CONST = { A: 1 };
type BadKey = keyof typeof WITHOUT_AS_CONST; // string
const WITH_AS_CONST = { A: 1 } as const;
type GoodKey = keyof typeof WITH_AS_CONST; // 'A'
実務ではas constとセットで運用しましょう。
用語解説:as const
TypeScriptでオブジェクトや配列を「リテラル型」として固定するための構文。型推論が具体的な値(リテラル)になるため、型抽出が正確になる。用語解説:リテラル型
具体的な値そのものを型として扱うTypeScriptの型。例:‘A’や1など。
4. 2026年の新定番:satisfies演算子との使い分け
■ as constだけでは不十分?satisfiesで型制約
type Colors = Record;
const THEME = {
primary: '#007',
secondary: 123, // エラーにしたいが、as constだけでは通る
} as const;
const THEME = {
primary: '#007',
secondary: '#6c7',
} as const satisfies Record;
type ThemeKey = keyof typeof THEME; // 'primary' | 'secondary'
用語解説:satisfies
TypeScript 4.9以降で導入された型演算子。オブジェクトが特定の型を満たしているかをチェックしつつ、型推論を広げない(リテラル型を維持)ことができる。用語解説:Record型
TypeScriptのユーティリティ型。Record<K, T>は「キーKと値Tのペア」を表現する。
■ キーだけじゃない!値の型も自動抽出
const APP_CONFIG = {
API_URL: 'https://api.example.com',
RETRY_COUNT: 3,
} as const;
type AppConfigValues = typeof APP_CONFIG[keyof typeof APP_CONFIG];
// 'https://api.example.com' | 3
5. 実務で使える逆引きスニペット集
■ ReactのPropsでバリアント定義
const BUTTON_VARIANTS = {
primary: 'bg-blue-500 text-white',
secondary: 'bg-gray-500 text-white',
danger: 'bg-red-500 text-white',
} as const;
type ButtonProps = {
variant: keyof typeof BUTTON_VARIANTS;
label: string;
};
const Button = ({ variant, label }: ButtonProps) => (
);
(TypeScriptのフォームバリデーションについては『TypeScriptフォームバリデーション徹底比較|Zod・Yup・React Hook Formの違いと選び方』をご参照ください)
■ APIレスポンスのエラーコード管理
const ERROR_MESSAGES = {
NOT_FOUND: 'データが見つかりませんでした。',
UNAUTHORIZED: '認証に失敗しました。',
SERVER_ERROR: 'サーバーエラーが発生しました。',
} as const;
function handleError(strong: keyof typeof ERROR_MESSAGES) {
const message = ERROR_MESSAGES[strong];
console.error(message);
}
6. FAQ|よくある疑問に回答
-
Q:keyof typeof を使うと型が string になるのはなぜ?
A:as constが付与されていないと、TypeScriptはプロパティをstring型として推論します。必ずas constを添えてください。 -
Q:ネストしたオブジェクトのキーは抽出できる?
A:基本は第1階層のみ。ネストしたキーを取得するにはkeyof typeof obj.nestedPropertyのようにパス指定が必要です。 -
Q:Enumとどちらが良い?
A:Tree-shakingや柔軟性の観点から、as const+keyof typeofが主流。Reactなどモダン開発ではこの組み合わせが推奨されています。 - Q:satisfiesはいつ使う?
A:オブジェクト構造に制約を設けたい場合に使います。型チェック+具体的な型推論を両立できます。 - Q:実行時にキーを取得できる?
A:keyof typeofはコンパイル時の型情報。実行時はObject.keys()を使いましょう。
まとめと次の一手
keyof typeofは型定義の自動化を実現し、私たちを保守性の低い作業から解放してくれる必須テクニックです。
- 二重管理の解消:オブジェクトをソースに型を作ることで修正漏れを防ぐ
- as constの重要性:リテラル型として抽出するために欠かせない
- 2026年のベストプラクティス:satisfiesで制約と推論を両立
ぜひコードをコピペして、まずは動かしてみてください。