項目58 コード生成を複雑な型の代替手段として検討する
型レベルのTypeScriptは非常に強力なツールだが、それが常に最適なわけでは無い
SQLのクエリから結果として得られる型を推論するのは、不可能ではないが正確でない型を生む可能性が高い
GROUP BY句やMAX式、$1というプレースホルダーなどを考慮した型を自作するのは困難
下記のコードに対する型定義は難易度高め
code:ts
async function getLatestBookByAuthor(db: Database, publisher: string) {
const result = await db.query(
SELECT author, MAX(year) FROM books GROUP BY author WHERE publisher=$1,
);
return result.rows;
}
複雑な型の操作には、型レベルのコードを書く代わりに、コードと型を生成することを検討する(codegen)
TypeScriptコード内で、タグ付きテンプレートリテラルを使って適切に書かれたSQLクエリを見つけ、DBと照合し入出力の型を含む型宣言ファイルを生成する
code:ts
import { sql } from '@pgtyped/runtime';
const selectLatest = sql`
SELECT author, MAX(year)
FROM books
GROUP BY author
WHERE publisher=$publisher
`;
async function getLatestBookByAuthor(db: Database, publisher: string) {
const result = await selectLatest.run({publisher}, db);
// ^? const result: any[]
return result;
}
pgtypedコマンドを使って型宣言を出力
npx pgtyped -c pgtyped.config.json
出力結果
code:ts
/** Types generated for queries found in "books-queries.ts" */
/** 'selectLatest' parameters type */
export interface selectLatestParams {
publisher: string;
}
/** 'selectLatest' return type */
export interface selectLatestResult {
author: string;
year: number;
}
/** 'selectLatest' query type */
export interface selectLatestQuery {
params: selectLatestParams;
result: selectLatestResult;
}
CICD上でコード生成とgit diffによる差分を確認することで、codegenの同期を図る