Skip to content

Commit 5ce68b2

Browse files
Add Either.transposeMapOption (#4741)
1 parent 17f40d6 commit 5ce68b2

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

.changeset/dirty-lemons-lie.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": minor
3+
---
4+
5+
Add Either.transposeMapOption

packages/effect/dtslint/Either.tst.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Array, Either, hole, pipe, Predicate } from "effect"
1+
import { Array, Either, hole, Option, pipe, Predicate } from "effect"
22
import { describe, expect, it } from "tstyche"
33

44
declare const string$string: Either.Either<string, string>
@@ -317,3 +317,36 @@ describe("Either", () => {
317317
).type.toBe<Either.Either<{ a: number; b: string; c: boolean }, never>>()
318318
})
319319
})
320+
321+
it("transposeMapOption", () => {
322+
expect(Either.transposeMapOption(Option.none(), (value) => {
323+
expect(value).type.toBe<never>()
324+
return string$string
325+
})).type.toBe<
326+
Either.Either<Option.Option<string>, string>
327+
>()
328+
expect(pipe(
329+
Option.none(),
330+
Either.transposeMapOption((value) => {
331+
expect(value).type.toBe<never>()
332+
return string$string
333+
})
334+
)).type.toBe<
335+
Either.Either<Option.Option<string>, string>
336+
>()
337+
expect(Either.transposeMapOption(Option.some(42), (value) => {
338+
expect(value).type.toBe<number>()
339+
return string$string
340+
})).type.toBe<
341+
Either.Either<Option.Option<string>, string>
342+
>()
343+
expect(pipe(
344+
Option.some(42),
345+
Either.transposeMapOption((value) => {
346+
expect(value).type.toBe<number>()
347+
return string$string
348+
})
349+
)).type.toBe<
350+
Either.Either<Option.Option<string>, string>
351+
>()
352+
})

packages/effect/src/Either.ts

+44
Original file line numberDiff line numberDiff line change
@@ -994,3 +994,47 @@ export const transposeOption = <A = never, E = never>(
994994
): Either<Option<A>, E> => {
995995
return option_.isNone(self) ? right(option_.none) : map(self.value, option_.some)
996996
}
997+
998+
/**
999+
* Applies an `Either` on an `Option` and transposes the result.
1000+
*
1001+
* **Details**
1002+
*
1003+
* If the `Option` is `None`, the resulting `Either` will immediately succeed with a `Right` value of `None`.
1004+
* If the `Option` is `Some`, the transformation function will be applied to the inner value, and its result wrapped in a `Some`.
1005+
*
1006+
* @example
1007+
* ```ts
1008+
* import { Either, Option, pipe } from "effect"
1009+
*
1010+
* // ┌─── Either<Option<number>, never>>
1011+
* // ▼
1012+
* const noneResult = pipe(
1013+
* Option.none(),
1014+
* Either.transposeMapOption(() => Either.right(42)) // will not be executed
1015+
* )
1016+
* console.log(noneResult)
1017+
* // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'None' } }
1018+
*
1019+
* // ┌─── Either<Option<number>, never>>
1020+
* // ▼
1021+
* const someRightResult = pipe(
1022+
* Option.some(42),
1023+
* Either.transposeMapOption((value) => Either.right(value * 2))
1024+
* )
1025+
* console.log(someRightResult)
1026+
* // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'Some', value: 84 } }
1027+
* ```
1028+
*
1029+
* @since 3.15.0
1030+
* @category Optional Wrapping & Unwrapping
1031+
*/
1032+
export const transposeMapOption = dual<
1033+
<A, B, E = never>(
1034+
f: (self: A) => Either<B, E>
1035+
) => (self: Option<A>) => Either<Option<B>, E>,
1036+
<A, B, E = never>(
1037+
self: Option<A>,
1038+
f: (self: A) => Either<B, E>
1039+
) => Either<Option<B>, E>
1040+
>(2, (self, f) => option_.isNone(self) ? right(option_.none) : map(f(self.value), option_.some))

0 commit comments

Comments
 (0)