Skip to content

Commit 907831e

Browse files
vinassefrancheeffect-bot
authored andcommitted
Add Either.transposeOption (#4466)
1 parent 73cdf99 commit 907831e

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

.changeset/quiet-tables-listen.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 Either.transposeOption

packages/effect/src/Either.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { TypeLambda } from "./HKT.js"
99
import type { Inspectable } from "./Inspectable.js"
1010
import * as doNotation from "./internal/doNotation.js"
1111
import * as either from "./internal/either.js"
12+
import * as option_ from "./internal/option.js"
1213
import type { Option } from "./Option.js"
1314
import type { Pipeable } from "./Pipeable.js"
1415
import type { Predicate, Refinement } from "./Predicate.js"
@@ -963,3 +964,38 @@ export {
963964
*/
964965
let_ as let
965966
}
967+
968+
/**
969+
* Converts an `Option` of an `Either` into an `Either` of an `Option`.
970+
*
971+
* **Details**
972+
*
973+
* This function transforms an `Option<Either<A, E>>` into an
974+
* `Either<Option<A>, E>`. If the `Option` is `None`, the resulting `Either`
975+
* will be a `Right` with a `None` value. If the `Option` is `Some`, the
976+
* inner `Either` will be executed, and its result wrapped in a `Some`.
977+
*
978+
* @example
979+
* ```ts
980+
* import { Effect, Either, Option } from "effect"
981+
*
982+
* // ┌─── Option<Either<number, never>>
983+
* // ▼
984+
* const maybe = Option.some(Either.right(42))
985+
*
986+
* // ┌─── Either<Option<number>, never, never>
987+
* // ▼
988+
* const result = Either.transposeOption(maybe)
989+
*
990+
* console.log(Effect.runSync(result))
991+
* // Output: { _id: 'Option', _tag: 'Some', value: 42 }
992+
* ```
993+
*
994+
* @since 3.14.0
995+
* @category Optional Wrapping & Unwrapping
996+
*/
997+
export const transposeOption = <A = never, E = never>(
998+
self: Option<Either<A, E>>
999+
): Either<Option<A>, E> => {
1000+
return option_.isNone(self) ? right(option_.none) : map(self.value, option_.some)
1001+
}

packages/effect/test/Effect/optional-wrapping-unwrapping.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { assert, describe, it } from "@effect/vitest"
22
import * as Effect from "effect/Effect"
3+
import * as Either from "effect/Either"
34
import * as Option from "effect/Option"
45

56
describe("Effect", () => {
@@ -17,3 +18,19 @@ describe("Effect", () => {
1718
}))
1819
})
1920
})
21+
22+
describe("Either", () => {
23+
describe("transposeOption", () => {
24+
it.effect("None", () =>
25+
Effect.gen(function*() {
26+
const result = yield* Either.transposeOption(Option.none())
27+
assert.ok(Option.isNone(result))
28+
}))
29+
30+
it.effect("Some", () =>
31+
Effect.gen(function*() {
32+
const result = yield* Either.transposeOption(Option.some(Either.right(42)))
33+
assert.deepStrictEqual(result, Option.some(42))
34+
}))
35+
})
36+
})

0 commit comments

Comments
 (0)