はじめに
表題の通りです。
Prismaの関数をラップした時、関数の戻り値の型にIncludeしたテーブルの型を含めたいです。
元々は以下の記事を参考にした「GetPayLoad」を使用して実現していました。
https://zenn.dev/yuyuyu_6/articles/9d3a2b5a7becad
しかし、Prisma4.11から5.11に更新してから型エラーで使えなくなってしまいました。
以下サンプルコードです。
async fetchUser<T extends Prisma.UserInclude>(
input: Prisma.UserFindManyArgs,
include?: T,
): Promise<Prisma.UserGetPayload<{ include: T }>[]> {
// 戻り値の型と不一致になる
return await this.prisma.User.findMany({
...input,
include: include,
});
}
上記が使えないと、Service層とUsecase層で処理の共通化が滞り、イケテナイコードを量産する羽目になりそうです。
本記事では上記の代替手段ついて記載します。
結論
代替を検討中にエラーを解消できてしまいました。。。
理由はわかりませんが、スプレット構文が原因でした。
以下のように修正すると動きます。
async fetchUser<T extends Prisma.UserInclude>(
input: Prisma.UserFindManyArgs,
include?: T,
): Promise<Prisma.UserGetPayload<{ include: T }>[]> {
// 戻り値の型と不一致になる
return await this.prisma.User.findMany({
where: input.where,
orderBy: input.orderBy,
skip: input.skip,
take: input.take,
cursor: input.cursor,
distinct: input.distinct,
include: include,
});
}
原因の予想ですが、PrismaではSelectとIncludeを同時におこなうとエラーになります。
元々UserFindManyArgsを展開すると、上記に反してエラーになるはずだったが、
バグか何かでそうならなかった。
それが修正されたのかなぁと。
でもスプレット構文の後にNullとかundefinedにしてもエラー発生するので、
わっかんねぇなぁって感じです。
代替案
前もって型を作成する
あんまりイケテナイとは思いますが最初に思いつく方法です。
シンプルゆえに一番確実です。
export type UserAndPost = User & {
Post: Post;
};
ジェネリクスを使わない
ジェネリクスを使わなくてもUserIncludeを使用すればリレーション先を含めた型を使用できます。
async fetchUser(
input: Prisma.UserFindManyArgs,
include?: Prisma.UserInclude,
): Promise<Prisma.UserGetPayload<{ include: Prisma.UserInclude }>[]> {
return await this.prisma.User.findMany({
...input,
include: include,
});
}
こうするともっとスマートかなと思います。
async fetchUser(
input: Prisma.UserFindManyArgs,
): Promise<Prisma.UserGetPayload<{ include: typeof input.include }>[]> {
return await this.prisma.User.findMany({
...input,
});
}
しかし、これで使用できるのはリレーション先のテーブルまでです。
リレーション先のリレーション先多重構造のテーブルの型は使用できません。
PromiseReturnType(没案)
公式でPrisma関数が返すオブジェクトの型を取得する時は「PromiseReturnType」を使えとあります。
https://www.prisma.io/docs/orm/prisma-client/type-safety/operating-against-partial-structures-of-model-types#problem-getting-access-to-the-return-type-of-a-function
これは今回のようにIncludeによって戻り値の型が変わる関数では意味がありませんでした。
そもそも型が合わないので呼び出せないです。
PrismaでNativeSQLを実行する場合とかはいいかもしれません。
終わり
スプレット構文でハマることが多く、こまったなぁって感じです。