2020年10月30日

データベースとTypeScriptの型定義を同期したいときに便利そうなライブラリ

下の動画を見て、やはりデータベース ⇔ バックエンド ⇔ フロントエンドの間でスキーマ定義が半自動的に同期される仕組みがあるというのは便利だな〜と思ったので、そのために使えそうなライブラリを調べました。


===
 
===


目標は、データベースを変更 → TypeScriptの型定義が半自動で更新される → バックエンドとフロントエンドの両方のプロジェクトで型定義が共有される、という状態にすることです。

バックエンドのDBアクセス、REST APIから、フロントエンドのReactコンポーネントのPropsまで、アプリケーション全体で共通の型定義を使いたい






動画で使われているのは、schemats というライブラリでした。これは、データベースからテーブルのスキーマを読み取って、TypeScriptの型定義を生成してくれるというもののようです。

サンプルコードやこちらのブログ記事を見ても分かるとおり、このライブラリは特にORMのようなものを介さずに自分で直接SQLクエリーを書いてデータベースにアクセスしたいという場合に向いているようです。



2. Knex.js / sql-ts 

Knex.js という軽量なDBアクセスライブラリを使う場合は、sql-ts もしくは上に挙げた schemats を利用して生成した型定義を使うことができそうです。




専用のスキーマ定義ファイルからTypeScriptの型定義を生成します。

このPrismaスキーマをデータベースから自動生成するワークフローと、まず自分でPrismaスキーマを書いて、それをマイグレーションでデータベースに反映するワークフローの2種類をサポートしているそうです。

DBからPrismaスキーマを生成

 
PrismaスキーマからDBに反映


ただ、こちらのNext.jsでのサンプルを見た感じでは、データベース⇔バックエンドの間では型定義の同期が取れていますがフロントエンド側まではそれが共有されていません。例えば個々のReactコンポーネントのPropsについてはそれぞれに型定義をおこなっているようです。フロントエンド側にまで型定義を共有出来る方法があるのかどうかについてはよく分かりませんでした。




TypeScriptを使う場合のORMライブラリとしてかなり人気があると思われるTypeORMですが、別途 typeorm-model-generator というCLIツールを組み合わせるとデータベースからTypeORM用のモデルクラスを生成することが出来るようです。




Node.js用のORMとしておそらく最も使われているSequelizeですが、これ向けにも sequelize-typescript-generator というCLIツールが見つかりました。Sequelize を採用することが決まっている場合は、こちらの組み合わせも良いかも知れません。 ただ、Sequlize向けに生成されたモデルクラスをそのままフロントエンド側で参照してReactコンポーネントなどで使えるかというと、それは厳しいのではないかと思います。



考察


「DBから生成した型定義をバックエンドからフロントエンドまで共通で使いたい」と書きましたが、結局よく考えてみると、

①バックエンド側でDBアクセスをするための型(テーブル単位)
②APIのインターフェースとしての型(ユースケース単位)
③フロントエンドのコンポーネント間でやり取りするための型(UI部品単位)

はそれぞれに用途が異なるので完全に同じものを使い回すというようなことは現実的ではなさそうです。

ただ、①②③の中でもカラム単位で見れば共通の定義を抽出して参照することは可能ではないかと思います。

例えば冒頭の動画で紹介されているように「通知メールの許可設定」を表すカラムについて、当初 Boolean だったものが後から Number に変更されたというようなケースでは、カラム単位で共通の型定義を参照していれば、一箇所が(コマンド一つで半自動的に)変更されれば(バックエンド、フロントエンド含めて)それを参照している全ての箇所がコンパイル時にエラーとなって容易に修正出来るようになるというイメージです。

このような用途で考えると、今回調べたライブラリの中では schemats は一度試してみる価値があるかも知れないと思いました。








🍻