こんにちは。TypeScriptの世界へようこそ。
現場でバリバリと開発をしていると、「APIから返ってくるこの複雑なレスポンス、わざわざ型定義を書き直すの面倒だな…」と思う瞬間、ありますよね。
今回は、TypeScriptの型システムの中でも特に強力な武器である「`infer` キーワード」を使って、「関数の戻り値から型を自動抽出する」という、実務で死ぬほど役に立つテクニックを伝授します。これさえマスターすれば、型定義の重複地獄から解放されますよ。
—
1. なぜ「戻り値の抽出」が必要なのか?
例えば、バックエンドから複雑なデータ構造が返ってくるAPIがあるとします。
// バックエンドが提供するAPI関数(実際にはもっと複雑なはずです)
async function fetchUserProfile() {
return {
id: 1,
name: “Alice”,
settings: { theme: “dark”, notifications: true },
roles: [“admin”, “editor”]
};
}
もし、この関数の戻り値を使って別の関数を作りたいとき、わざわざ `interface UserProfile { … }` と手書きしていませんか?
もしAPI側の型が変わったら、手書きのインターフェースを全部修正しなければなりません。これはバグの温床です。「関数の実行結果から型を勝手に抜き出してくれればいいのに」――それを実現するのが `infer` です。
—
2. 「infer」の正体:型の中の「変数」
`infer` は、「型の中で使う一時的な変数」だと考えてください。
「この関数の戻り値が `T` 型だとしたら、その `T` を抽出してくれ!」という命令を、条件分岐(Conditional Types)の中で記述します。
基本的な抽出ツール:ReturnType
TypeScriptには、標準で `ReturnType
type MyReturnType
このコードの読み解き方はこうです:
1. `T extends (…args: any[]) => …` : 「Tは関数型ですか?」と聞いています。
2. `… => infer R` : 「もし関数なら、その戻り値を `R` という名前の変数に入れて!」と指示しています。
3. `? R : never` : 「関数だったら抽出した `R` を返し、そうでなければ `never`(型なし)にするよ」という意味です。
これが、TypeScriptが裏側で型を推論している正体です。
—
3. 実践:複雑なAPIレスポンスから型を抽出する
では、実際に現場で使うパターンを見てみましょう。
// 1. 先ほどのAPI関数
const fetchUserProfile = async () => ({
id: 1,
name: “Alice”,
settings: { theme: “dark” as const },
});
// 2. inferを使って、関数の戻り値型だけを抽出
type UserProfile = ReturnType
// 3. 抽出した型をインターフェースのように扱う
function printUserName(user: UserProfile) {
console.log(user.name); // 型安全!
}
ここで重要なのは `typeof` です。`fetchUserProfile` は値(関数そのもの)ですが、`typeof` をつけることで型情報に変換し、それを `ReturnType` に渡しているのです。
—
4. 陥りやすい罠と解決策
初学者が必ず一度はハマるポイントがいくつかあります。ここをクリアすれば、もう中級者です。
罠①:Promiseの解決に失敗する
`fetchUserProfile` のような `async` 関数は、常に `Promise
解決策:
`Awaited` という便利なユーティリティ型を組み合わせます。
type RawResult = ReturnType
type User = Awaited
これで、非同期処理のラップを剥がした「真の戻り値型」が手に入ります。
罠②:関数の引数で「infer」を使おうとして混乱する
`infer` は「抽出」する場所によって役割が変わります。戻り値だけでなく、関数の引数も抽出可能です。
type FirstArg
// 使用例
type MyFunc = (id: number, name: string) => void;
type Arg0 = FirstArg
—
5. まとめ:TypeScriptの極意
今回紹介した `infer` や `ReturnType` は、「型を手書きするな、コードの構造から自動生成せよ」というTypeScriptの哲学を体現するものです。
- `infer` は型の中の変数である
- `typeof` で値を型に昇格させる
- `ReturnType` や `Awaited` で複雑な型を「逆算」する
最初は魔法のように見えるかもしれませんが、コンパイラは常に「この関数の戻り値は何か?」を解析しています。私たちはその解析結果を、`infer` を使って少しだけお裾分けしてもらっているに過ぎないのです。
ここをマスターすれば、もう「型定義の修正に追われる日々」とはおさらばです。ぜひ、今日書いているコードで `ReturnType
それでは、また次の深淵でお会いしましょう。ハッピーコーディング!