こんにちは!TypeScriptの型定義の世界へようこそ。チーフアーキテクトの私です。
日々のフロントエンド開発、本当にお疲れ様です。「`string`や`number`は分かってきたけれど、型パズルみたいな高度な書き方になると、途端に頭が真っ白になる…」そんな風に悩んでいませんか? 大丈夫です、安心してください。最初は誰もがそこで一度はつまずきます。
今回は、TypeScriptの型定義の中でも、特に「おおっ、魔法みたいだ!」と感動できる、しかし使いこなせば実務でめちゃくちゃ強力な武器になる「Mapped TypesにおけるKey Remapping(`as`句によるキー名の変換)」について、じっくりとお話ししていきますね。
難しい専門用語はなるべく置いておいて、身近な例えから紐解いていきましょう。
—
1. そもそも Mapped Types と Key Remapping ってなに?
イメージしてみてください。あなたは文房具屋さんで、ノートやペンの「ラベル」を一新する作業を任されました。
ダンボールに入っている既存のラベルには、「name」「age」「price」と英語で書かれています。これを、お店の棚卸し用ルールに合わせて、全部「`get` + 元の名前」という形に書き換えたい。しかも、手作業ではなく「自動スタンプ」のような仕組みで一瞬で終わらせたい。
この「既存のオブジェクトのキー(ラベル)を、ルールに従って別の名前にパパッと変換しちゃう仕組み」こそが、Mapped Typesの`as`句(Key Remapping)なんです。
TypeScript 4.1以降で導入されたこの`as`句を使うと、オブジェクトのキーをループで回しながら「このキーはこういう名前に変えちゃって!」と指示できるようになりました。
—
2. 身近な例え:お買い物アプリの「ゲッター自動生成」
例えば、Webアプリを作っていて、次のようなユーザーのプロフィール情報を表す型があったとします。
type User = {
name: string;
age: number;
};
ここで、「このユーザーデータの値を安全に取得するための専用関数(ゲッター)を、オブジェクトの型から自動で作っちゃいたいな」と思ったとします。具体的には、`name` から `getName` という関数を、`age` から `getAge` という関数を生み出したいわけです。
手動で一つずつ書くのは面倒だし、プロパティが増えたときにメンテが大変ですよね。そこで登場するのが、`as`句を使ったキーのリマップです。
まずは、百聞は一見に如かず。実際のコードを見てみましょう。
// 元となるユーザーの型
type User = {
name: string;
age: number;
};
// 【マジック!】as句を使ってキー名を「get + 先頭大文字の名前」に変換する型
type CreateGetters
// ① [K in keyof T] で元のキーを1つずつ順番に取り出す(name, ageなど)
// ② as `get${Capitalize
[K in keyof T as `get${Capitalize
};
// 試しに使ってみましょう!
type UserGetters = CreateGetters
/
生成される UserGetters の正体はこれになります:
{
getName: () => string;
getAge: () => number;
}
/
どうでしょう? `getName` と `getAge` という関数を生み出す型が、自動で組み上がりましたね!
ここで使っているテンプレートリテラル型(“ `get${…}` “)と、TypeScriptの便利な組み込み型 `Capitalize`(最初の文字を大文字にするやつです)が組み合わさることで、まるで呪文のようにキレイなキー名が作れるんです。
—
3. つまずきやすいポイントと「大丈夫だよ」のフォロー
さて、ここで「なんだか記号が多くて目が回るよ…」と思ったそこのあなた。めちゃくちゃ自然な反応です。特に初心者の頃は、このあたりの記述が暗号に見えて当然です。
ポイントを3つに分解して整理してみましょう。
1. `keyof T` で、オブジェクトのキー一覧(`”name” | “age”`)を取り出す。
2. `in` で、そのキーを1個ずつループして舐めていく。
3. `as 変換後の名前` で、今の名前をポイッと捨てて、新しい名前に書き換える。
これだけです。特に `as` の右側で「元のキー名(`K`)」をテンプレートリテラルに埋め込むときは、TypeScriptに対して「`K`は文字列だよ(`string & K`)」と少しだけ優しく教えてあげる必要があるのが、実務でよくあるハマりどころ。
「あ、コンパイラが型を安心できるように念のためキャストしてあげてるんだな」と、軽く受け流しておけばOKです。
—
4. さらに実用的な応用:不要なキーの「消去(フィルタリング)」
Key Remappingのすごいところは、名前を変えるだけじゃなく、「いらないキーを消し去る(`never`を返す)」ことができる点です。
例えば、「名前に `id` が付くプロパティだけは、今回の処理から除外したい!」というとき、`as`句の中で条件分岐ができます。
type Product = {
id: string;
name: string;
price: number;
};
// id以外のプロパティだけを残す魔法の型
type RemoveId
// もしキーが ‘id’ なら never(=存在しないもの)にする!それ以外はそのままのキーにする
[K in keyof T as K extends ‘id’ ? never : K]: T[K];
};
type FilteredProduct = RemoveId
/
生成される FilteredProduct の姿:
{
name: string;
price: number;
}
(idがきれいに消えています!)
/
これ、実務の現場でAPIのレスポンス型を整形するときなどにめちゃくちゃ使います。「フロントエンド側で触らせたくない機密系のキーや管理IDを、一括で型レベルでシャットアウトする」といったテクニックですね。知っているだけで、コードのスマートさが段違いになります。
—
おわりに
Mapped TypesのKey Remapping(`as`句)、いかがでしたでしょうか?
最初は「型なのにまるでプログラミング言語みたいだな、難しそう…」と感じたかもしれませんが、一つひとつの部品(ループ、名前の変更、条件分岐)を紐解いていくと、私たちの開発を強力にサポートしてくれる心強い相棒であることが分かります。
もしエディタ上で赤線が出てしまったり、思い通りの型にならなくても、焦る必要は全くありません。一つひとつ、小さなサンプルコードで試しながら、自分のものにしていってくださいね。
あなたのTypeScriptライフが、より快適で楽しいものになりますように。チーフアーキテクトの私でした!また次回の記事でお会いしましょう。

コメント