Open5

関数ネームスペースとしてのclassを考える

terrierscriptterrierscript

ここで扱うClass

  • JavaScript / TypeScriptにおけるクラス
  • readonlyなメンバーしか持たないクラス
  • extendしない
  • あくまで名前空間の方便として扱うclass
terrierscriptterrierscript

例えばこんな感じ

// class pattern
export class TaskRepository {
  prisma: PrismaClient
  constructor(prisma: PrismaClient) {
    this.prisma = prisma
  }
  getTaskById = (id: string) => {
    return this.prisma.task.findUnique({ where: { id } })
  }
}

Objectとして書くならこんな具合

// object pattern
export const generateTaskRepository = (prisma: PrismaClient) => {
  return {
    getTaskById: (id: string) => {
      return prisma.task.findUnique({ where: { id } })
    }
  }
}

export type TaskRepositoryObj = ReturnType<typeof generateTaskRepository>
terrierscriptterrierscript

classにする場合の課題

  • 真のprivateを作りづらい(最近は#privateができるけど)
  • superを意識したいか?
  • prototypeの罠にはまらないように注意が必要
  • 継承より移譲を意識しづらい

object(closure)にする場合の課題

  • 内部で関数同士を呼ぶ場合ちょっとややこしい。
  • 型定義のためにReturnType<typeof>などで再定義が必要(classはこれを兼ねている)
  • 肥大化したとき読みづらい(気がする)
  • 初期化時に何でも出来すぎる
  • implementsによる制限をかけづらい
terrierscriptterrierscript

Interfaceの補完を効かせられるか?

class

interface ITaskRepository {
  getTaskById(id: string): Promise<Task | null>
}
// class pattern
export class TaskRepository implements ITaskRepository {
  prisma: PrismaClient
  constructor(prisma: PrismaClient) {
    this.prisma = prisma
  }
}

object (closure)

書き方に工夫が必要。一旦変数として定義してあげて返せばいける

export const generateTaskRepository = (prisma: PrismaClient): ITaskRepository => {
  const impl: ITaskRepository = {

  }
  return impl
}