構造的型付けと serialize 境界

カミナシ堂

セッション

16:00 ~ 16:30

### 主題 TypeScript の構造的型付け (structural typing) が serialize 境界で引き起こす問題と、その解決策についてお話したいと思います。 構造的型付けは、外部とのインターフェース部分で json をはじめとする様々な形式にデータを serialize する場面で、不用意に serialize してしまうと出力すべきでないデータまで serialize してしまうというミスを犯しがちです。ユーザーの目に触れる query string であったり、値のチェックが厳密な GraphQL variables では特に問題となってしまいます。 加えて、最終的に serialize するまでの過程で、データの前処理や変換を伴うにも関わらず、変換前の型が構造的部分型を満たしてしまい、必要な変換が漏れてしまうといった場合があります。 本トークでは、検索条件を表現するデータ型を例として、zod や valibot に代表されるバリデータライブラリを使って serialize 直前に出力する値を保証する方法を説明します。データ変換は brand 機能による公称型 (nominal typing) で型チェックを強制し validation を補助しています。 どういったデータの変換処理で問題が起きやすいのか、型をどのように考えると強固な設計になりやすいのか、プロダクトでのリアルな事例をもとにご紹介できればと思います。 ### 背景 Remix で書かれたレストラン予約サイトを運用しています。GraphQL バックエンドを持ち、Remix の loader を BFF 的に扱うアーキテクチャを取っています。 旧システムから段階的なリニューアルを進めているのですが、今回問題となったのは検索画面で、後方互換性を維持するため、画面ごとに少しずつ異なる検索条件を持つ必要がある場面でした。 それらのわずかに異なる検索条件が、省略可能なフィールドの多い検索条件というデータの特性も相まって、互換性のある構造的部分型となり、型チェックが効かない状況に陥りました。 加えて、扱うべき検索条件のデータ型の峻別ができていなかったがために、不用意に処理をまとめてしまい、必要な型変換が漏れてしまい、意図しない情報を含む serialize で問題を引き起こしてしまいました。 また SSR のために TanStack Query の prefetch 機能を使っていたことも問題の発見を遅らせてしまいました。 この失敗事例をもとに、型安全に変換を行いながら、適切な serialize 前の validation を行うようにした改善について、ご紹介したいと考えています。 ### 想定聴衆 外部とのインターフェース部分でデータの serialize を行った経験のある方が対象です。 structural typing と nominal typing の違い、zod や valibot などの validator ライブラリ、それら提供する brand 機能についても、トークの中で説明するので前提知識は不要です。

tak-onda_image
恩田 崇

株式会社一休 CTO室 / ソフトウェアエンジニア

1978年生まれ、京都在住。 フルスタックでなんでも屋。 フロントエンドとの関わりは IE4/DHTML の頃から。 2023年9月から、一休レストランのフロントエンドアーキテクトを努める。 Next.js App Router から Remix に置き換えた。

github_linktwitter_link