0
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?

effect-tsでLSPプラグインの利用

Last updated at Posted at 2025-09-13

Effect-tsのLSPプラグインがあるみたいなので、それを試してみる

参考

Layerからグラフの生成

依存関係なし

domain_liveのような変数にカーソルを合わせると
グラフを表示できる機能が追加されるようだ
※Vueなどのプロジェクトでは競合する何かがあるのか、うまく動かなかった

image.png

表示するグラフは以下
image.png

ソースコード

import { Duration, Effect, Layer } from "effect"

type type_employee_id = string
type type_department_id = string

// ---- employee ----

interface interface_employee {
  employee_id: type_employee_id
  employee_name: string
  department_id: type_department_id
}

class database_employee_service extends Effect.Service<database_employee_service>()("database_employee_service", {
  succeed: ({
    get_one_employee: (employee_id: type_employee_id) =>
      Effect.gen(function*() {
        console.log("get_one_employee start")
        yield* Effect.sleep(Duration.seconds(5))
        const data: interface_employee = {
          employee_id,
          employee_name: "test employee",
          department_id: test_department_id
        }
        console.log("get_one_employee end")
        return data
      })
  })
}) {}

// ---- department ----

interface interface_department {
  department_id: type_department_id
  department_name: string
}

class database_department_service extends Effect.Service<database_department_service>()("database_department_service", {
  succeed: ({
    get_one_department: (department_id: type_department_id) =>
      Effect.gen(function*() {
        console.log("get_one_department start")
        yield* Effect.sleep(Duration.seconds(3))
        const data: interface_department = {
          department_id,
          department_name: "test department"
        }
        console.log("get_one_department end")
        return data
      })
  })
}) {}

// ---- test data ----

const test_employee_id: type_employee_id = "e_00_test"
const test_department_id: type_department_id = "d_00_test"

// ---- service ----------------

const get_data_from_2db = Effect.gen(function*() {
  const DatabaseEmployee = yield* database_employee_service
  const result_employee = yield* DatabaseEmployee.get_one_employee(test_employee_id)
  console.log(result_employee)
  const DatabaseDepartment = yield* database_department_service
  const result_department = yield* DatabaseDepartment.get_one_department(result_employee.department_id)
  console.log(result_department)
})

const service_live = Layer.mergeAll(database_employee_service.Default, database_department_service.Default)

const program_2db = get_data_from_2db.pipe(
  Effect.provide(service_live)
)

// ---- layer -----------------

interface employee_data {
  employee: interface_employee
  department: interface_department
}

class domain_employee_service extends Effect.Service<domain_employee_service>()("domain_employee_service", {
  effect: Effect.gen(function*() {
    const DatabaseEmployee = yield* database_employee_service
    const DatabaseDepartment = yield* database_department_service
    return {
      get_one_employee_data: (
        employee_id: type_employee_id
      ) =>
        Effect.gen(function*() {
          const employee = yield* DatabaseEmployee.get_one_employee(employee_id)
          const department = yield* DatabaseDepartment.get_one_department(employee.department_id)
          const result: employee_data = {
            employee,
            department
          }
          return result
        })
    }
  }),
  dependencies: [service_live]
}) {}

const get_data_from_domain = Effect.gen(function*() {
  const DomainEmployee = yield* domain_employee_service
  const result_employee = yield* DomainEmployee.get_one_employee_data(test_employee_id)
  console.log(result_employee)
})

const domain_live = Layer.mergeAll(
  domain_employee_service.Default
)

const program_domain = Effect.provide(get_data_from_domain, domain_live)

// ---- Entry Point ----
Effect.runPromise(program_domain)

動作結果

get_one_employee start
get_one_employee end
get_one_department start
get_one_department end
{
  employee: {
    employee_id: 'e_00_test',
    employee_name: 'test employee',
    department_id: 'd_00_test'
  },
  department: { department_id: 'd_00_test', department_name: 'test department' }
}

依存関係が存在あり

Layerの作り方が不十分だと以下のように下位のLayerが表示されてしまう

image.png

import { Context, Duration, Effect, Layer } from "effect"

type type_employee_id = string
type type_department_id = string

// ---- employee ----

interface interface_employee {
  employee_id: type_employee_id
  employee_name: string
  department_id: type_department_id
}

class database_employee extends Context.Tag("database_employee")<
  database_employee,
  {
    readonly get_one_employee: (
      employee_id: type_employee_id
    ) => Effect.Effect<interface_employee>
  }
>() {}

const DatabaseServiceEmployee = database_employee.of({
  get_one_employee: (employee_id) =>
    Effect.gen(function*() {
      console.log("get_one_employee start")
      yield* Effect.sleep(Duration.seconds(5))
      const data: interface_employee = {
        employee_id,
        employee_name: "test employee",
        department_id: test_department_id
      }
      console.log("get_one_employee end")
      return data
    })
})

const DatabaseLayerEmployee = Layer.succeed(
  database_employee,
  {
    get_one_employee: (employee_id) =>
      Effect.gen(function*() {
        console.log("get_one_employee start")
        yield* Effect.sleep(Duration.seconds(5))
        const data: interface_employee = {
          employee_id,
          employee_name: "test employee",
          department_id: test_department_id
        }
        console.log("get_one_employee end")
        return data
      })
  }
)

// ---- department ----

interface interface_department {
  department_id: type_department_id
  department_name: string
}

class database_department extends Context.Tag("database_department")<
  database_department,
  {
    readonly get_one_department: (
      department_id: type_department_id
    ) => Effect.Effect<interface_department>
  }
>() {}

const DatabaseServiceDepartment = database_department.of({
  get_one_department: (department_id) =>
    Effect.gen(function*() {
      console.log("get_one_department start")
      yield* Effect.sleep(Duration.seconds(3))
      const data: interface_department = {
        department_id,
        department_name: "test department"
      }
      console.log("get_one_department end")
      return data
    })
})

const DatabaseLayerDepartment = Layer.succeed(
  database_department,
  {
    get_one_department: (department_id) =>
      Effect.gen(function*() {
        console.log("get_one_department start")
        yield* Effect.sleep(Duration.seconds(3))
        const data: interface_department = {
          department_id,
          department_name: "test department"
        }
        console.log("get_one_department end")
        return data
      })
  }
)

// ---- test data ----

const test_employee_id: type_employee_id = "e_00_test"
const test_department_id: type_department_id = "d_00_test"

// ---- service ----------------

const get_data_from_2db = Effect.gen(function*() {
  const DatabaseEmployee = yield* database_employee
  const result_employee = yield* DatabaseEmployee.get_one_employee(test_employee_id)
  console.log(result_employee)
  const DatabaseDepartment = yield* database_department
  const result_department = yield* DatabaseDepartment.get_one_department(result_employee.department_id)
  console.log(result_department)
})

const program_2db = get_data_from_2db.pipe(
  Effect.provideService(database_employee, DatabaseServiceEmployee),
  Effect.provideService(database_department, DatabaseServiceDepartment)
)

// ---- layer -----------------

interface employee_data {
  employee: interface_employee
  department: interface_department
}

class domain_employee extends Context.Tag("domain_employee")<
  domain_employee,
  {
    readonly get_one_employee_data: (
      employee_id: type_employee_id
    ) => Effect.Effect<employee_data>
  }
>() {}

const DomainLayerEmployee = Layer.effect(
  domain_employee,
  Effect.gen(function*() {
    const DatabaseEmployee = yield* database_employee
    const DatabaseDepartment = yield* database_department
    return {
      get_one_employee_data: (
        employee_id: type_employee_id
      ) =>
        Effect.gen(function*() {
          const employee = yield* DatabaseEmployee.get_one_employee(employee_id)
          const department = yield* DatabaseDepartment.get_one_department(employee.department_id)
          const result: employee_data = {
            employee,
            department
          }
          return result
        })
    }
  })
)

const get_data_from_domain = Effect.gen(function*() {
  const DomainEmployee = yield* domain_employee
  const result_employee = yield* DomainEmployee.get_one_employee_data(test_employee_id)
  console.log(result_employee)
})

const DomainLive = DomainLayerEmployee.pipe(
  Layer.provide(DatabaseLayerEmployee),
  Layer.provide(DatabaseLayerDepartment)
)

const program_domain = Effect.provide(get_data_from_domain, DomainLive)

// ---- Entry Point ----
Effect.runPromise(program_domain)

Layerの変換

Layerの変換を2ステップで実行できる

ステップ1 Layerを配列で並べて変換

以下のようにLayerを配列で並べる

const test = [
  database_employee_service.Default,
  database_department_service.Default
]

上記の変数を右クリックして、Refactorを選択
image.png

Prepare layers for automatic compositionを選択
image.png

以下のように変換される

const test =[database_employee_service.Default,
database_department_service.Default] as any as Layer.Layer<database_department_service | database_employee_service>

ステップ2 再度変換

上記の変数を右クリックして、Refactorを選択
image.png

Compose layers automatically with target output servicesを選択
image.png

以下のように変換される

const test =database_department_service.Default.pipe(Layer.merge(database_employee_service.Default))
0
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
0
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?