Repositoryパターンの全件取得処理を型と関数で実装してみた
TypeScript / フック / Repositoryパターン
これまでTypeScriptでRepositoryパターンを実装する時にオブジェクト指向で実装してたんですが、型と関数でも実装してみました。
まずは手始めに全件取得処理を型と関数で実装してみます。
Repositoryの共通部分をフックで実装する
まずはRepositoryの共通部分を実装してみます。
Repositoryを型と関数で実装する場合、個別のテーブルやスキーマ情報をフックできる関数を作ると扱いやすいです。
レコードを全件取得するRepositoryの実装例はこんな感じになります。
const useFindAllRepository = <RECORD, MODEL>(
  table: PrismaClient,
  schema: {
    toModel: (record: RECORD): MODEL
  }
) => ({
  findAll: (): Promise<MODEL | null> => {
    // フックしたtableを使ってレコードを全件取得する
    const records: RECORD[] = await table.findMany()
    // フックしたスキーマを使ってモデルに変換する
    return records.map(schema.toModel)
  }
} as const)
useRepository 関数はテーブルとスキーマ(load関数だけですが)を受け取って、findAll関数を持つオブジェクトを返しています。
UserRepositoryをフックで実装する
次はUserRepositoryです。
さっそく先ほどのuseFindAllRepositoryを使って実装してみます。
type User = {
  id: number
  email: string
}
const useUserRepository = () => {
  const { findAll } = useFindAllRepository<Users, User>(
    prisma.users,
    {
      load: (record: Users): User =>
        ({ id: record.id, email: record.email }),
    }
  )
  return { findAll } as const
}
type UserRepository = ReturnType<typeof useUserRepository>
このように、useFindAllRepositoryにUserのテーブルとスキーマを渡してあげるとUserの配列を返すfindAll関数が取得できるので、その関数をそのまま使えばUserRepositoryを実装できます。
RetutnTypeを使ったUserRepository型の定義
UserRepository型の定義にはReturnTypeを使っています。
type UserRepository = ReturnType<typeof useUserRepository>
ReturnTypeは戻り値の型を返すUtility Typeです。
ここではUserRepositoryの型が、useUserRepository関数の戻り値の型である
{
  findAll: () => Promise<User[]>
}
となります。
ReturnTypeについて詳しく知りたい方は公式ドキュメントもご覧ください。
まとめ
やってみたらRepositoryパターンは意外と簡単に型と関数で実装できました。
今回は引数を受け取らないfindAll関数のみの実装でしたが、次はIDなどの引数を受け取るパターンも実装してみようと思います。
