TypeScriptの型システムと日々格闘している中級エンジニアの皆さん、こんにちは。
「APIから返ってくるスネークケースのレスポンスデータを、フロントエンドの作法に合わせてキャメルケースに一括変換したい……でも、毎回手動で型定義を書くのは面倒くさいし、変更に追いつかない」
――そんな絶望感に襲われた夜はないだろうか。
実務をやっていると、「バックエンドの都合」と「フロントエンドの都合」の狭間で、オブジェクトのキー名をパパッと動的に変換したくなるシーンに必ず直面する。そんなとき、昔のTypeScriptなら `Record<...>` や複雑な交差型(Intersection Types)を組み合わせて何とかごまかすしかなかった。
しかし、今の私たちには Mapped Typesにおける `as` 句(キーの再マッピング) がある。これを知っているかどうかで、型定義のスマートさと、コードレビューでドヤ顔できるかどうかが決まると言っても過言ではない。
今回は、この `as` 句を使ったキーの再マッピングについて、裏側の仕組みから実務で即座に使えるテクニックまで、シニアの視点からみっちり解説していこう。
—
1. そもそも `as` 句によるキーの再マッピングとは何か?
Mapped Types(マップ型)の基本は、既存のオブジェクトの型を走査して新しい型を作り出すことだ。例えば `{ [K in keyof T]: … }` という書き方は、中級以上のエンジニアなら目をつぶっていても書けるはずだ。
しかし、TypeScript 4.1で導入された `as` 句を使うと、走査している最中のキー(`K`)の名前自体を別の名前に書き換えたり、不要なキーをフィルタリングしたりできるようになった。
文法はこうだ:
type MappedWithRename
[K in keyof T as 変換処理
};
この `as` の右側にはテンプレートリテラル型や条件分岐(Conditional Types)を組み込めるため、表現力が爆発的に向上する。
—
2. ブラウザやTypeScriptのコンパイラは裏側でどう処理しているのか?
ここで少し、TypeScriptの「エンジンが裏側で何をやっているか」という話をしよう。
TypeScriptはブラウザのJavaScriptエンジンそのものではなく、あくまで「コンパイル時に型を検証する静的解析レイヤー」だ。しかし、このMapped Typesの再マッピングは、TypeScriptの型チェッカー(TSServer)の中で非常にアグレッシブな計算を行っている。
コンパイラは以下のステップでこの型を評価している:
1. キーの列挙(Keyof Evaluation): まず対象のオブジェクトから `keyof T` でキーのユニオン型を抽出する。
2. テンプレートリテラル型・条件型の適用: `as`句の右側に評価が走り、ユニオンの各要素に対して文字列操作や `never` への置換が行われる。
3. キーの正規化と重複排除: もし変換後のキーが重複した場合(例: 異なるスネークケースのキーが同じキャメルケースに潰された場合)、型システムはユニオンとしてマージするか、エラーとして検知する。
4. 型定義のキャッシュ: ここがパフォーマンスの肝なのだが、TypeScriptは複雑な再マッピング結果をキャッシュする。ただし、過度に複雑な条件分岐を `as` 内に詰め込むと、エディタの補完(IntelliSense)が重くなる原因(いわゆる「TypeScriptがフリーズする現象」)になる。
実務では、この「コンパイラに負荷をかけすぎないスマートな書き方」を意識することが、チーム全体の開発体験(DX)を守る上で極めて重要だ。
—
3. 【実践】現場で使えるコピペ可能なコード例
百聞は一見にしかず。実務でよくある「APIのスネークケースをキャメルケースに変換する」という要件を、`as` 句を使って美しく型安全に解決してみよう。
以下のコードは、そのままエディタに貼り付けて挙動を確認できる。
/
- ユーティリティ型: スネークケース(snake_case)の文字列をキャメルケース(camelCase)に変換する
/
type CamelCase = S extends `${infer Head}_${infer Tail}`
? `${Head}${Capitalize
: S;
/
- 実務ユースケース1: APIレスポンスのキーをすべてキャメルケースに変換しつつ、
- 特定のプレフィックスを持つキーだけを抽出・変換するマップ型
/
type ToCamelCaseKeys
// keyof T から取得したキー K を string に制約し、as 句でキャメルケースに変換
[K in keyof T as CamelCase
};
// — テスト用のAPIレスポンス型 —
interface UserApiResponse {
user_id: string;
first_name: string;
last_name: string;
is_active: boolean;
created_at: string;
}
// 変換後のフロントエンド用型
type UserEntity = ToCamelCaseKeys
/
- 変換結果(UserEntityの中身):
- {
- userId: string;
- firstName: string;
- lastName: string;
- isActive: boolean;
- createdAt: string;
- }
/
const sampleUser: UserEntity = {
userId: “usr_12345”,
firstName: “Taro”,
lastName: “Yamada”,
isActive: true,
createdAt: “2026-03-30T00:00:00Z”, // 型通りに補完・チェックされる!
};
さらに一歩進む:不要なキーの「フィルタリング」
`as` 句の真骨頂は、変換だけでなく「除外(Filtering)」ができる点だ。`as` の評価結果に `never` を返すと、そのプロパティは自動的に生成されるオブジェクトから消え去る。
以下の例を見てほしい。特定のプレフィックスを持つキーだけを残すマジックだ。
/
- ユーティリティ型: 特定のプレフィックス(例: ‘meta_’)を持つキーだけを残し、
- キー名からプレフィックスを剥ぎ取るマップ型
/
type ExtractAndStripPrefix
// K が Prefix で始まる場合はプレフィックスを剥がし、始まらない場合は never にして除外する
[K in keyof T as K extends `${Prefix}${infer Rest}` ? Rest : never]: T[K];
};
interface RawDocument {
id: string;
content: string;
meta_author: string;
meta_version: number;
meta_is_published: boolean;
}
// ‘meta_’ で始まるキーだけを抽出し、キー名から ‘meta_’ を取り除く
type DocumentMetadata = ExtractAndStripPrefix
/
- 変換結果(DocumentMetadata):
- {
- author: string;
- version: number;
- is_published: boolean;
- }
/
const metadata: DocumentMetadata = {
author: “Dev Team”,
version: 2,
is_published: true,
};
このテクニックを知っていれば、GraphQLやREST APIから渡される雑多なメタデータや内部管理用のキーを、フロントエンドのコンポーネントが扱いやすい綺麗な型へ一瞬で整形できる。余計な手動の型定義ファイルを何枚も書く必要はもうない。
—
4. シニアからの実践アドバイス・注意点
この `as` 句による再マッピングは強力だが、実務で使う際にはいくつか注意すべき「罠」がある。
1. 型パズルへの依存に注意する
あまりに複雑な条件分岐を入れ子にすると、コードが「読めない魔術」になり、チームメンバーが誰も触れなくなってしまう。複雑な文字列操作を行う場合は、小さく汎用的なユーティリティ型(今回の `CamelCase` のようなもの)に切り出し、意図をコメントで残すこと。
2. IDEのパフォーマンス劣化を気にする
巨大なスキーマ(数百プロパティを持つオブジェクトなど)に対して深すぎる再マッピングを行うと、VSCodeの補完(Type checking)が重くなる。もしエディタの動作がカクつくようになったら、ジェネリクスの制約(constraints)を見直そう。
3. ランタイムの挙動(JavaScript)を忘れない
型定義を変換しているだけであり、実際のオブジェクトのランタイムのプロパティ名が変わるわけではない。APIからスネークケースで返ってきたデータを、この型に合わせてそのままコンポーネントに渡すと、中身は `undefined` になる。型変換と同時に、ランタイム側のキー変換関数(lodashの `camelCase` を使った再帰的変換など)をセットで実装する必要がある点を忘れないようにしよう。
—
まとめ
Mapped Typesの `as` 句によるキーの再マッピングは、TypeScriptによるフロントエンド設計の自由度を一段上のステージに引き上げてくれる。
「バックエンドのスキーマ変更に追われて型定義の修正に毎度疲弊している」という現場であれば、今回紹介したテクニックを導入するだけで、ボイラープレートコードを劇的に削減できるはずだ。
型は単なるエラーチェックの道具ではなく、「ドキュメントであり、チームの共通言語」である。ぜひ今日の業務から、あなたのコードベースにも取り入れてみてほしい。

コメント