Slide 1

Slide 1 text

inferと仲良くなる10分間 TSKaigi 2026 2026/05/24

Slide 2

Slide 2 text

自己紹介 Infixer(インフィクサー) 株式会社タイミー フロントエンドエンジニア HTMLとCSSが大好きなマークアップおじさんです。 X(Twitter) GitHub Blog Bluesky Cosense

Slide 3

Slide 3 text

こんなお話をします inferキーワードの読み方、考え方、使い方を理解する Utility Types Conditional Types infer 束縛変数 パターンマッチング

Slide 4

Slide 4 text

Utility Types

Slide 5

Slide 5 text

Utility Types 型変換を容易にするためのユーティリティ型としてTypeScriptにはUtility Typesが 用意されています。 Utility Typesは、グローバルに利用することが可能

Slide 6

Slide 6 text

ReturnTypeについて 型パラメータ`T`に与えた関数の戻り値の型を得ることができるもの 1 2 3 4 5 6 7 8 9 // 型に対して使う場合 type Fn = () => string; type R1 = ReturnType; // string // 値(関数)に対して使う場合は typeof が必要 function getUser() { return { name: "infixer", age: 37 }; } type R2 = ReturnType; // { name: string; age: number }

Slide 7

Slide 7 text

ReturnTypeの型をみる `T extends (...args: any) => any> = T extends (...args: any)` って何? 🤔 `infer R ? R`って何?🤔

Slide 8

Slide 8 text

Conditional Types

Slide 9

Slide 9 text

Conditional Types 型の条件分岐のこと。JavaScriptの三項演算子のように使う。 入出力の型の関係を記述するのに便利 1 2 3 4 type IsString = T extends string ? true : false; type A = IsString<"hello">; // true type B = IsString<123>; // false `T extends U ? X : Y` 「T が U を満たすなら X、そうでなければ Y」

Slide 10

Slide 10 text

もう一度ReturnTypeの型をみる 1 2 3 4 type ReturnType any> = T extends (...args: any) => infer R ? R : any; Conditional Typesで条件を記述していることがわかる inferって何?

Slide 11

Slide 11 text

infer

Slide 12

Slide 12 text

inferとは? Conditional Typesで使用できる一時的な型変数の宣言 変数の型を推論(infer)して型変数の中身を決定するも の inferの宣言は、extendsの右辺でしか使えない 宣言した型変数は、true分岐の中ならどこでも使える

Slide 13

Slide 13 text

inferの読み方 1 2 3 4 5 type Example = T extends { data: infer U } ? U : never; type T1 = Example<{ data: string }>; // string type T2 = Example<{ data: User[] }>; // User[] type T3 = Example<{ message: string }>; // never もしT が { data: ... } の形をしているなら、 その data の中身の型に U と名前をつけて取り出す(束縛する) → そして U を返す そうでなければ → never を返す

Slide 14

Slide 14 text

再度ReturnTypeの型をみる 1 2 3 4 type ReturnType any> = T extends (...args: any) => infer R ? R : any; もしT型が (...args: any) => any を形をしているなら、
 その関数の戻り型として割り当てられている型を`R`と名前をつけて型パラメー タとして取り出す(束縛する)
   → そしてR型を返す
 そうでなければ → any型を返す

Slide 15

Slide 15 text

inferは型の世界に束縛変数を導入したもの 束縛変数 名前と値 (型) が結びついた変数のこと `infer U` Uに結びつく型が入力に応じて動的に決まる スコープ true分岐の中のみ有効である

Slide 16

Slide 16 text

Conditional Types + inferは型のパターンマッチング Conditional Typesで型レベルの条件分岐ができる 特定のパターンに合致した中身の型に名前をつけて取 り出せる つまりパターンマッチング パターンマッチング(英: Pattern matching、パターン照合)とは、データを検索する場合 に特定のパターンが出現するかどうか、またどこに出現するかを特定する手法のことであ る。 wikipedia:パターンマッチング

Slide 17

Slide 17 text

Conditional Typesで型レベルの条件分岐ができる inferを使うことで中身の型に名前をつけて取り出せる つまりパターンマッチっぽい

Slide 18

Slide 18 text

inferの使用例

Slide 19

Slide 19 text

弊社の例)配列の中身の文字列が重複しているかチェックする 1 2 3 4 5 6 7 8 9 // やりたくない:npmパッケージをそのまま読み込むと、約3000個分のアイコン分ダウンロードすることになる import 'material-symbols'; // 型だけimport import type { MaterialSymbol } from 'material-symbols'; const _availableMaterialSymbols = [ 'call', 'check', 'arrow_back', ] as const satisfies MaterialSymbol[]; プロダクト全体で使うアイコンを、 Material Symbolsで管理している。 直接npmから使うと、本来使うことのないアイコンもすべて含まれるのでパ フォーマンスが悪い。 Material Symbolsの型だけを使い、実際に使うアイコン名だけを格納した配列 で管理。 同じアイコン名を記述できないように文字列の重複チェックをしたい

Slide 20

Slide 20 text

文字列の重複チェックにinferを使う 1 2 3 4 5 6 7 8 9 10 type ArrayToUnion = T[number]; type IsUnique = T extends readonly [infer First, ...infer Rest] ? First extends ArrayToUnion ? `"${First & string}"` : IsUnique : never; type ValidateUniqueArray = IsUnique extends never ? T : IsUnique; `infer`を使って配列の先頭とそれ以外に分割する 先頭の要素が分割した配列内の要素にあるか調べる 要素があれば重複しているので文字列リテラル型で返す 残りの要素を再帰的に処理する

Slide 21

Slide 21 text

実際の型エラー

Slide 22

Slide 22 text

まとめ

Slide 23

Slide 23 text

まとめ inferは型の世界に束縛変数を導入した Conditional Types + inferはパターンマッチしてい るんだなと捉える 自分で書く機会は少なくても、読めるようになる と見え方が変わる

Slide 24

Slide 24 text

https://github.com/microsoft/TypeScript/blob/4076ff8fd6c91c07f6baefa0843e22e33168e164/tests/cases/conformance/types/conditional/inferTypes1.ts

Slide 25

Slide 25 text

ご清聴ありがとうございました

Slide 26

Slide 26 text

参照 Utility Types: https://www.typescriptlang.org/docs/handbook/utility-types.html Conditional Types: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html inferと実例 UnArray / TypeScript一人カレンダー: https://zenn.dev/okunokentaro/ articles/01gm6sbe97g0jnzj2ed24va0vv Type inference in conditional types: https://github.com/microsoft/TypeScript/pull/21496 Announcing TypeScript 4.1: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/ オーバーロードされた関数型から引数の型や返り値の型を取り出す方法: https://zenn.dev/uhyo/articles/ typescript-overload-infer パターンマッチング: https://ja.wikipedia.org/wiki/ %E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%83%9E%E3%83%83%E3%83%81%E3%83%B3% E3%82%B0