TypeScriptのユーティリティ型とMapped Typesを初心者向けに徹底解説!型の便利機能とは?
生徒
「TypeScriptを使っていると、すでにある型の項目を一部だけ使ったり、全てを必須にしたりしたくなるのですが、新しく型を作り直すしかないのでしょうか?」
先生
「そんな時に便利なのが『ユーティリティ型』です。既存の型をベースにして、魔法のように新しい型をサッと作ることができるんですよ。」
生徒
「魔法みたいですね!具体的にどうやって使うのか、初心者でもわかりますか?」
先生
「もちろんです。パソコンの操作に慣れていない方でもイメージしやすい例えを使いながら、基本的な仕組みからじっくり解説していきますね!」
1. ユーティリティ型とは何か?
TypeScriptにおけるユーティリティ型とは、一言で言うと「型を加工するための便利な道具箱」のことです。プログラミングでは、データに名前を付けて管理するために「型」というルールを作ります。しかし、状況によっては「このルールを少しだけ変えたいな」と思うことがあります。
例えば、お弁当の注文メニューというルールがあるとします。通常は「ごはん」「メインのおかず」「副菜」の三つがセットですが、人によっては「ごはんだけ」や「おかず抜き」で注文したい場合もありますよね。ユーティリティ型を使えば、元の「全部入りメニュー」というルールを壊さずに、「一部だけ選べるメニュー」という新しいルールを自動的に作り出すことができるのです。
これを使うことで、似たような型を何度も手作業で書く必要がなくなり、入力ミスを減らして効率的にプログラムを書くことができるようになります。初心者の方は、まず「型を便利に作り変えるショートカット機能」だと思っておけば間違いありません。
2. 全てを任意にするPartialユーティリティ
まず最初に覚えたいのが、Partialという型です。これは、型の中にある全ての項目を「あってもなくても良いもの(任意)」に変えてくれる魔法です。専門用語では「オプションにする」と言います。
例えば、ユーザー登録の情報を考えてみましょう。名前、メールアドレス、住所、電話番号が必須のルールになっている場合、編集画面などでは「住所だけ変更したい」ということがあります。この時、全ての項目をわざわざ入力しなくても済むようにするのが、この機能の役割です。
interface User {
name: string;
age: number;
email: string;
}
// Partialを使うことで、全ての項目が「あってもなくても良い」状態になります
type OptionalUser = Partial<User>;
let updateData: OptionalUser = {
name: "たろう"
};
// ageやemailがなくてもエラーになりません
このコードでは、元のUserという型を加工して、名前だけでも受け付けられる新しいルールを作っています。もしこれを使わないと、毎回「名前だけの型」「年齢だけの型」と別々に用意しなければならず、非常に手間がかかってしまいます。
3. 必要な項目だけを抜き出すPickユーティリティ
次に便利なのが、Pickという型です。これは、たくさんの項目がある型の中から、必要なものだけを「つまみ食い」して新しい型を作る機能です。英語の「ピックアップ(拾い上げる)」と同じ意味だと考えると分かりやすいでしょう。
例えば、商品の詳細情報という型には「商品名」「価格」「在庫数」「製造元」「説明文」などたくさんのデータが入っています。しかし、スマートフォンの画面に表示するリストでは「商品名」と「価格」だけで十分な場合もありますよね。そんな時に、特定の項目だけを抽出して身軽な型を作ることができます。
interface Product {
id: number;
name: string;
price: number;
description: string;
stock: number;
}
// Product型から、nameとpriceだけを取り出した新しい型を作ります
type SimpleProduct = Pick<Product, "name" | "price">;
const item: SimpleProduct = {
name: "おいしいリンゴ",
price: 150
};
実行結果を確認すると、無駄なデータを含まないスッキリとした型ができていることがわかります。これにより、プログラムが扱うデータの範囲が明確になり、間違いが起こりにくくなります。
{ "name": "おいしいリンゴ", "price": 150 }
4. 特定の項目を除外するOmitユーティリティ
Pickとは反対に、特定の項目だけを「取り除く」のがOmitという型です。これは「除外する」という意味があります。たくさんの項目がある中で「これとこれ以外は全部使いたい」という時に非常に役立ちます。
例えば、アンケートフォームの回答データから、プライバシーに関わる「氏名」だけを消して、統計データとして扱いたい場合を想像してください。項目が何十個もある場合、一つずつ選ぶのは大変ですが、いらないものだけを指定して消す方が圧倒的に楽ですよね。
interface Survey {
userName: string;
age: number;
feedback: string;
date: string;
}
// Survey型からuserNameだけを取り除いた型を作ります
type AnonymousSurvey = Omit<Survey, "userName">;
const data: AnonymousSurvey = {
age: 25,
feedback: "とても使いやすかったです!",
date: "2026-04-02"
};
このように、元の形を活かしつつ不要な部分を削ぎ落とすことで、データの安全性を高めたり、管理をしやすくしたりすることができます。プログラミングでは、必要なものだけを見せるという考え方がとても大切なのです。
5. 書き換えを禁止するReadonlyユーティリティ
データを「見るだけで、書き換えてはいけない」というルールにしたい時は、Readonlyを使います。これは「読み取り専用」という意味で、一度決めた値を後から変更しようとすると、パソコンが「勝手に変えたらダメですよ!」と注意してくれるようになります。
例えば、設定ファイルのデータや、銀行の口座番号などは、途中でプログラムが間違えて書き換えてしまうと大変なことになります。あらかじめこの型を適用しておくことで、ヒューマンエラーを防ぐ強力なガードレールになってくれます。
interface Config {
apiUrl: string;
retryCount: number;
}
// 全ての項目を読み取り専用にします
const mySettings: Readonly<Config> = {
apiUrl: "https://example.com/api",
retryCount: 3
};
// もしここで mySettings.retryCount = 5; と書こうとするとエラーになります
初心者の方は、最初は自由に値を変更できた方が楽だと感じるかもしれませんが、プログラムが大きくなってくると、どこで値が変わったのか分からなくなるのが一番の悩みになります。最初から変更できないルールを作っておくことは、自分自身の将来のミスを防ぐ賢い方法なのです。
6. Mapped Typesの基本概念を理解する
さて、ここからは少しレベルアップしてMapped Types(マップドタイプス)についてお話しします。これは、先ほど紹介したユーティリティ型たちの「中身の仕組み」のようなものです。専門的な言葉で言えば、既存の型のプロパティ(項目)をループ処理のように回して、新しい型を生成する技術です。
「ループ処理」というのは、同じ作業を繰り返すことです。例えば、クラス全員の名簿に対して、一人ずつ順番に「出席番号」を割り振っていくようなイメージです。Mapped Typesを使うと、「元の型にある全ての項目に対して、一気に特定のルールを適用する」という指示が出せます。
ユーティリティ型は、あらかじめ用意された便利な道具でしたが、Mapped Typesを使えば、自分オリジナルの「魔法の加工ツール」を自作することも可能になります。TypeScriptが非常に柔軟で強力だと言われる理由の一つが、この機能にあります。
7. Mapped Typesの具体的な書き方
Mapped Typesの構文には、特殊な記法を使います。具体的には [K in keyof T] という形がよく使われます。これは「型Tの中にあるキー(項目名)を、一つずつKという名前で取り出して処理する」という意味です。パソコンに詳しくない方には少し呪文のように見えるかもしれませんが、順番に見ていけば大丈夫です。
例えば、全ての項目の種類を無理やり「文字列(string)」に変えてしまうような型を作ってみましょう。どんなデータが来ても、最終的には文字として扱いたいという特殊なケースで役立ちます。
type AllString<T> = {
[P in keyof T]: string;
};
interface Scores {
math: number;
english: number;
}
// Scoresの項目は数値(number)でしたが、全て文字(string)の型に変換されます
type StringScores = AllString<Scores>;
const myGrades: StringScores = {
math: "満点",
english: "合格"
};
この AllString というのが、私たちが自作した加工ツールです。このように、一つひとつの項目を個別に書き直すのではなく、一括でルールを適用できるのがMapped Typesの最大のメリットです。
8. ユーティリティ型を活用するメリット
ここまで学んできたユーティリティ型やMapped Typesを活用すると、どのような良いことがあるのでしょうか。大きなメリットは三つあります。
一つ目は、コードの重複が減ることです。同じような項目を持つ型をいくつも作らなくて済むため、プログラムが短く読みやすくなります。二つ目は、修正が楽になることです。元の型を一つ修正すれば、それを利用しているユーティリティ型も自動的に反映されるため、直し忘れによるバグが激減します。
三つ目は、開発者の意図が伝わりやすくなることです。例えば Pick<User, "id"> と書いてあれば、他のプログラマーが見た時に「ああ、ここではユーザーのIDだけを使いたいんだな」とすぐに理解できます。型は単なるルールではなく、プログラマー同士のコミュニケーションツールでもあるのです。
9. 実践的な活用シーンをイメージしよう
最後に、実際の開発でどのようにこれらが使われているか、より具体的なイメージを持ってみましょう。Webサイトの制作では、サーバーからデータを取得して表示する場面がたくさんあります。
サーバーから届くデータは非常に量が多いですが、画面上の小さなボタンの中に表示したいのはその一部だけかもしれません。また、入力フォームでユーザーが文字を打ち込んでいる途中は、まだ全てのデータが揃っていないため、一時的に「項目が足りなくてもOK」という状態にする必要があります。こうした「データの状態の変化」に合わせて、ユーティリティ型は影で支えるヒーローのように活躍しています。
最初は難しく感じるかもしれませんが、自分でコードを書いて、パソコンから「エラーです!」と怒られながら試行錯誤することで、少しずつこの便利さが体に馴染んできます。まずは一番簡単な Partial から使い始めて、徐々に Pick や Omit に挑戦してみるのが上達の近道です。