PostgreSQLとTypeScriptを組み合わせて開発している方なら、SQLクエリの型安全性に悩んだ経験があるのではないでしょうか。クエリ結果の型を手動で定義するのは面倒ですし、スキーマ変更時に型定義の更新を忘れるとランタイムエラーの原因になります。

そんな課題を解決するツールとして、pg-typesafeがHacker Newsで話題になっていたので、試してみた感想をまとめます。

pg-typesafeとは

pg-typesafeは、PostgreSQLのクエリに対してTypeScriptの型を自動生成するツールです。最大の特徴は、ランタイム依存がゼロで、既存のコードをほぼ変更せずに導入できる点にあります。

通常のpgライブラリのクエリがそのまま型付きになるので、学習コストがほとんどかかりません。

使い方はシンプル

導入手順は驚くほどシンプルです。まず開発依存としてインストールします。

npm i -D pg-typesafe

次に、データベースに接続して型定義を生成します。

npm exec pg-typesafe -- --connectionString postgres://user:pass@localhost/mydb

これでsrc/defs.gen.tsが生成されます。あとはPoolをキャストするだけですね。

import type { TypesafePool } from "./defs.gen.ts";
export const pool = new Pool() as TypesafePool;

この状態で再度pg-typesafeを実行すると、コード中のクエリを解析して、パラメータと戻り値の型が自動的に付与されます。

何が嬉しいのか

従来のアプローチとの違いを整理してみました。

ORMとの比較:PrismaやDrizzleのようなORMは便利ですが、複雑なクエリではSQLを直接書きたくなる場面が多々あります。pg-typesafeなら生のSQLを維持しつつ型安全性を得られるので、パフォーマンスチューニングもしやすいです。

手動型定義との比較:クエリごとにインターフェースを定義する方法は確実ですが、スキーマ変更時のメンテナンスコストが高い。pg-typesafeは自動生成なので、npm exec pg-typesafeを再実行するだけで済みます。

既存のpgコードとの互換性:既存プロジェクトに後から導入できるのが地味に大きなメリットです。コードのリファクタリングが不要で、型安全性だけを追加できます。

制限事項も理解しておく

いくつか注意点もあります。SQLクエリが文字列リテラルとしてコード中に記述されている必要があり、動的に組み立てたクエリには対応していません。ただし、これはSQLインジェクション防止の観点からも望ましい制約だと思います。

pg_backgroundのようなPostgreSQL拡張機能と組み合わせる場合も、クエリ部分の型安全性は確保できます。

類似ツールとの位置づけ

TypeScript×PostgreSQLの型安全ツールとしては、PgTyped、Slonik、Zapatos等がありますが、pg-typesafeはゼロランタイム依存という点で差別化されています。ビルドツールチェーンへの影響が最小限なので、CI/CDパイプラインへの統合もスムーズですね。

DuckDBのような分析用途のデータベースとは異なり、本番のOLTPワークロードで型安全性を担保したい場面に最適です。PostgreSQLのレースコンディション対策と合わせて、堅牢なデータベースアクセス層を構築できるでしょう。

まとめ

pg-typesafeは、「生SQLを書きたいけど型安全も欲しい」という開発者のニーズにピッタリなツールです。導入コストが低く、既存プロジェクトにも後付けできるのが魅力的ですね。PostgreSQL + TypeScriptで開発している方は、一度試してみる価値があると思います。

参考リンク: