Skip to content

Commit 6bc6da5

Browse files
mattiamanzatieffect-bot
authored andcommitted
Add type-level utils to asserting layer types (#5920)
1 parent 1f0d4a4 commit 6bc6da5

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

.changeset/dry-cycles-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": minor
3+
---
4+
5+
Add type-level utils to asserting layer types

packages/effect/dtslint/Layer.tst.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Layer, Schedule } from "effect"
1+
import { Context, Layer, Schedule } from "effect"
22
import { describe, expect, it } from "tstyche"
33

44
interface In1 {}
@@ -19,6 +19,8 @@ interface Out3 {}
1919

2020
declare const layer3: Layer.Layer<Out3, Err3, In3>
2121

22+
class TestService1 extends Context.Tag("TestService1")<TestService1, {}>() {}
23+
2224
describe("Layer", () => {
2325
it("merge", () => {
2426
expect(Layer.merge).type.not.toBeCallableWith()
@@ -40,4 +42,28 @@ describe("Layer", () => {
4042
expect(Layer.retry(layer1, Schedule.recurs(1))).type.toBe<Layer.Layer<Out1, Err1, In1>>()
4143
expect(layer1.pipe(Layer.retry(Schedule.recurs(1)))).type.toBe<Layer.Layer<Out1, Err1, In1>>()
4244
})
45+
46+
it("ensureSuccessType", () => {
47+
expect(layer1.pipe(Layer.ensureSuccessType<Out1>())).type.toBe<Layer.Layer<Out1, Err1, In1>>()
48+
})
49+
50+
it("ensureErrorType", () => {
51+
const withoutError = Layer.succeed(TestService1, {})
52+
expect(withoutError.pipe(Layer.ensureErrorType<never>())).type.toBe<Layer.Layer<TestService1, never, never>>()
53+
54+
const withError = layer1
55+
expect(withError.pipe(Layer.ensureErrorType<Err1>())).type.toBe<Layer.Layer<Out1, Err1, In1>>()
56+
})
57+
58+
it("ensureRequirementsType", () => {
59+
const withoutRequirements = Layer.succeed(TestService1, {})
60+
expect(withoutRequirements.pipe(Layer.ensureRequirementsType<never>())).type.toBe<
61+
Layer.Layer<TestService1, never, never>
62+
>()
63+
64+
const withRequirement = layer1
65+
expect(withRequirement.pipe(Layer.ensureRequirementsType<In1>())).type.toBe<
66+
Layer.Layer<Out1, Err1, In1>
67+
>()
68+
})
4369
})

packages/effect/src/Layer.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,3 +1226,55 @@ export const updateService = dual<
12261226
layer,
12271227
map(context(), (c) => Context.add(c, tag, f(Context.unsafeGet(c, tag))))
12281228
))
1229+
1230+
// -----------------------------------------------------------------------------
1231+
// Type constraints
1232+
// -----------------------------------------------------------------------------
1233+
1234+
/**
1235+
* A no-op type constraint that enforces the success channel of a Layer conforms to
1236+
* the specified success type `ROut`.
1237+
*
1238+
* @example
1239+
* import { Layer } from "effect"
1240+
*
1241+
* // Ensure that the layer produces the expected services.
1242+
* const program = Layer.succeed(MyService, new MyServiceImpl()).pipe(Layer.ensureSuccessType<MyService>())
1243+
*
1244+
* @since 3.20.0
1245+
* @category Type constraints
1246+
*/
1247+
export const ensureSuccessType =
1248+
<ROut>() => <ROut2 extends ROut, E, RIn>(layer: Layer<ROut2, E, RIn>): Layer<ROut2, E, RIn> => layer
1249+
1250+
/**
1251+
* A no-op type constraint that enforces the error channel of a Layer conforms to
1252+
* the specified error type `E`.
1253+
*
1254+
* @example
1255+
* import { Layer } from "effect"
1256+
*
1257+
* // Ensure that the layer does not expose any unhandled errors.
1258+
* const program = Layer.succeed(MyService, new MyServiceImpl()).pipe(Layer.ensureErrorType<never>())
1259+
*
1260+
* @since 3.20.0
1261+
* @category Type constraints
1262+
*/
1263+
export const ensureErrorType = <E>() => <ROut, E2 extends E, RIn>(layer: Layer<ROut, E2, RIn>): Layer<ROut, E2, RIn> =>
1264+
layer
1265+
1266+
/**
1267+
* A no-op type constraint that enforces the requirements channel of a Layer conforms to
1268+
* the specified requirements type `RIn`.
1269+
*
1270+
* @example
1271+
* import { Layer } from "effect"
1272+
*
1273+
* // Ensure that the layer does not have any requirements.
1274+
* const program = Layer.succeed(MyService, new MyServiceImpl()).pipe(Layer.ensureRequirementsType<never>())
1275+
*
1276+
* @since 3.20.0
1277+
* @category Type constraints
1278+
*/
1279+
export const ensureRequirementsType =
1280+
<RIn>() => <ROut, E, RIn2 extends RIn>(layer: Layer<ROut, E, RIn2>): Layer<ROut, E, RIn2> => layer

0 commit comments

Comments
 (0)