Mapped Typesの「as」で型を操る:オブジェクト変換の最終兵器
フロントエンド開発の現場で、APIから返ってきたレスポンスをそのまま画面に表示して「ハイ終わり!」なんてことは稀だ。大抵の場合、バックエンドの命名規則(snake_case)をフロントエンドのUIコンポーネント用(camelCase)に変換したり、特定のプレフィックスを付与したりする「泥臭い変換処理」が発生する。
そんな時、`any` で逃げていないか? もしくは、わざわざ新しい型を手書きして管理していないか?
今日は、TypeScriptのMapped Typesにおける `as` キーワードを使った「キーの再マッピング」という、知っているだけでコードの保守性が劇的に変わるテクニックを伝授する。これを使えば、型システムが勝手に変換後の型を追跡してくれるようになる。
—
なぜ「as」によるキー変換が必要なのか?
Mapped Typesは、あるオブジェクトのキーを反復処理して新しい型を作る強力な武器だ。しかし、従来の `{ [K in keyof T]: T[K] }` だけでは、キーの名前自体を変えることはできなかった。
そこで登場したのが `as` による再マッピングだ。これを使うと、テンプレートリテラル型と組み合わせて、「キーの命名規則を自動変換する」という魔法が使えるようになる。
ブラウザの裏側で起きていること
まず前提として押さえておきたいのは、TypeScriptは「コンパイル時にのみ存在する概念」だということ。ブラウザ上のJavaScriptエンジン(V8など)は、この `as` による型変換を一切知らない。
TypeScriptのコンパイラは、この型定義を解析する際、抽象構文木(AST)を操作して、キーを変換した後の新しいインターフェースを静的に構築する。つまり、実行時のオーバーヘッドはゼロだ。型安全を担保しつつ、ランタイムは極めてクリーン。これがこの手法を採用する最大のメリットだ。
—
実践:snake_case を camelCase に一撃で変換する
現場で最も遭遇する「APIレスポンスの変換」を例にしよう。`user_id` を `userId` に変えたい時、手書きのインターフェースは修正漏れの温床だ。
以下は、`as` とテンプレートリテラル型を組み合わせた、汎用的な変換ユーティリティだ。
// 文字列をキャメルケースに変換するユーティリティ型
type CamelCase = S extends `${infer P1}_${infer P2}${infer P3}`
? `${P1}${Uppercase
: S;
// 汎用的に使える、オブジェクトのキーを変換するMapped Types
type RenameKeys
[K in keyof T as K extends string ? CamelCase
};
// — 実務での利用例 —
interface ApiUserResponse {
user_id: number;
first_name: string;
is_active: boolean;
}
// キーが自動的に camelCase に変換された新しい型が生成される
// { userId: number; firstName: string; isActive: boolean; } と同義
type User = RenameKeys
const user: User = {
userId: 1,
firstName: “Taro”,
isActive: true,
};
console.log(user.userId); // 型安全にアクセス可能
—
さらに一歩先へ:特定のフィールドを除外する「as never」
再マッピングのもう一つの強力な武器が、`as never` によるフィルタリングだ。
「特定の条件(例えば、特定のプレフィックスを持つキー)を除外したい」という要件はよくある。
type RemovePrivateFields
// “_” で始まるキーは never にすることで型から除外される
[K in keyof T as K extends `_${string}` ? never : K]: T[K]
};
interface UserData {
id: number;
name: string;
_internal_cache: string; // 外部に見せたくないデータ
}
// { id: number; name: string; } だけが抽出される
type PublicUserData = RemovePrivateFields
—
シニアエンジニアからの助言:使いどころを見極める
このテクニックは極めて強力だが、「型定義が複雑になりすぎないか?」という視点を忘れてはいけない。
1. 可読性: あまりに複雑な再帰的型定義は、チームメンバーを混乱させる。ドキュメントには「何のための変換か」を明記しておくこと。
2. 型エラーの難解さ: 複雑なMapped Typesでエラーが出た際、VSCodeのヒントは時に難解なエラーメッセージを吐き出す。デバッグの際は `type Debug
3. 過剰な抽象化の禁止: 数回しか使わない変換なら、潔く手でインターフェースを書いた方が早いこともある。「DRY原則」と「読みやすさ」のバランスを常に天秤にかけるのが、プロの仕事だ。
まとめ
- `as` を使うと、Mapped Typesの中でキーの変換(リネーム)が可能になる。
- テンプレートリテラル型と組み合わせれば、命名規則の変換も型レベルで自動化できる。
- `as never` を使えば、不要なキーのフィルタリングもスマートに行える。
- ブラウザ上ではJSとして何も残らないため、パフォーマンスへの影響はない。
この手法を使いこなせるようになれば、君のコードは「動く」だけでなく「堅牢で、変更に強い」ものへと進化するはずだ。ぜひ、明日のコミットから試してみてほしい。

コメント