3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Prisma][TypeScript]Includeしたテーブルの型を使用したい

Posted at

はじめに

表題の通りです。
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を実行する場合とかはいいかもしれません。

終わり

スプレット構文でハマることが多く、こまったなぁって感じです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?