🐢

Prismaのクエリ情報から型定義を取得する

2024/09/15に公開

目的

PrismaClientを使って取得したデータの型定義が欲しかったのですが、手動定義ではなくクエリ情報から自動定義したいので調査しました

方法

Prisma documentの該当ページを参考に、Prisma.validatorユーティリティ型で抽出しました。

// 1. validatorにクエリの種類に応じて作成した情報を渡す
const fetchLatestInvoicesQuery =
  Prisma.validator<Prisma.invoicesFindManyArgs>()({
    select: {
      amount: true,
      id: true,
      customer: {
        select: {
          name: true,
          image_url: true,
          email: true,
        },
      },
    },
    orderBy: {
      date: "asc",
    },
    take: 5,
  });

// 2. getpayloadで型定義を取得
export type LatestInvoice = Prisma.invoicesGetPayload<typeof fetchLatestInvoicesQuery>;

// 3. 取得した型定義は、フェッチデータの返り値などに適用する
const data: LatestInvoice = await prisma.invoices.findMany(fetchLatestInvoicesQuery);

余談

型を加工したいケース、たとえばネストしたクエリプロパティの型を変更したい場合、Prisma.getPayloadを都度適用する必要があります。

// Prisma.getPayloadで取得した型
export type LatestInvoice = Prisma.invoicesGetPayload<typeof fetchLatestInvoicesQuery>;

// ネストした型プロパティを変更する型を独自定義
export type DeepPropertyReplacer<SourceType, TargetProp, ReplaceType> =
  SourceType extends never
    ? SourceType
    : {
        [k in keyof SourceType]: k extends TargetProp
          ? ReplaceType
          : DeepPropertyReplacer<SourceType[k], TargetProp, ReplaceType>;
      };

// 期待どおりに動く
export type LatestInvoiceReplacedNestProperty = DeepPropertyReplacer<Prisma.invoicesGetPayload<typeof fetchLatestInvoicesQuery>,
'targetKey', number>
;

// Prisma.getPayloadで取得した型を再利用しても、期待どおりに動かない
export type LatestInvoiceReplacedNestProperty = DeepPropertyReplacer<LatestInvoice,
'targetKey', number>
;

Discussion