# Result overview
A Result
can either Ok
or Ko
:
Ok
signifies the operation succeededKo
signifies the operation failed
A Result
, being a simple variable, may also allow you to handle multiple operations that may fail, without throwing / stopping on the first failure
const divide = (a, b) => {
if (b === 0) {
throw Err.of('cannot divide {a} by {b}', { a, b })
}
return a / b
}
const [ok, ko] = pipe(
[ [3,1], [3,0], [1,2], [4,0] ],
Arr.map(([a, b]) => Result.tryCatch(() => divide(a, b))),
Arr.separate
)
# Summary
# Types
# Ok
interface Ok<T> {
_tag: Tags.Ok
ok: T
}
# Ko
interface Ko<T> {
_tag: Tags.Ko
ko: T
}
# Result
type Result<A, E = unknown> = Ok<A> | Ko<E>
# Functions
# Result.ok
# Description
Create an Ok
value
<T>(value: T) => Ok<T>
# Result.ko
# Description
Create a Ko
value
<T>(value: T) => Ko<T>
# Result.isOk
# Description
Check if the result is Ok
<A, B>(result: Result<A, B>) => result is Ok<A>
# Example
const result = Result.ok(1)
if (Result.isOk(result)) {
console.log(result.ok)
}
# Result.isKo
# Description
Check if the result is Ko
<A, B>(result: Result<A, B>) => result is Ko<B>
# Example
const result = Result.ko(new Error('some error occured'))
if (Result.isKo(result)) {
console.log(result.ko)
}
# Result.isResult
# Description
Check if unknown variable is a Result
<A = unknown, B = unknown>(result: unknown) => result is Result<A, B>
# Result.fromOption
# Description
Create a Result
from an optional value
<E = unknown>(onNone: () => E) => <A>(option: Option<A>) => Result<A, E>
# Example
const user: Result<User, Error> = pipe(
users,
Arr.find(u => u.id === 'xxxx'),
Result.fromOption(() => new Error('could not find user'))
)
# Result.get
# Description
Returns value if the result is Ok
, or throws value if result is Ko
.
<A, E = unknown>(result: Result<A, E>) => A
# Result.tuple
# Description
Transforms the result into a tuple [ value, error ]
<A, E = unknown>(result: Result<A, E>) => [Option<A>, Option<E>]
# Example
const [value, error] = Result.tryCatch(() => {
throw new Error('Unknown')
})
expect(value).toBe(undefined)
expect(error?.message).toBe('Unknown')
# Result.map
# Description
Map over the Ok
value of the Result
.
The callback is not called if the result is Ko
.
<A, B>(fn: (value: A) => B) => <E = unknown>(result: Result<A, E>) => Result<B, E>
# Example
const result = pipe(
Result.ok(1),
Result.map(nb => nb + 1)
)
expect(result).toEqual(Result.ok(2))
# References
Result.mapError
- If you want to map over theKo
value instead
# Result.mapError
# Description
Map over the Ko
value of the Result
.
The callback is not called if the result is Ok
.
<B, E = unknown>(fn: (value: E) => B) => <A>(result: Result<A, E>) => Result<A, B>
# Example
const result = pipe(
Result.ko(new Error('some error')),
Result.mapError(Err.chain('operation failed'))
)
# References
Result.map
- If you want to map over theOk
value instead
# Result.join
# Description
Flatten a Result
in a Ok
value
<A, E>(result: Result<Result<A, E>, E>) => Result<A, E>
# Example
const result: Result<Result<number, Error>, unknown> = pipe(
Result.ok(1),
Result.map(nb => nb >= 0
? Result.ok(nb + 1)
: Result.ko(new Error('only positives'))
)
)
const after: Result<number, Error | unknown> = Result.join(result)
# References
Result.chain
- Chain another operation returning aResult
over anOk
valueResult.catchError
- Chain another operation returning aResult
over anKo
value
# Result.chain
# Description
Chain another operation returning a Result
over an Ok
value
<A, B, E = unknown>(fn: (value: A) => Result<B, E>) => (result: Result<A, E>) => Result<B, E>
# Example
const result: Result<number, Error | unknown> = pipe(
Result.ok(1),
Result.chain(nb => nb >= 0
? Result.ok(nb + 1)
: Result.ko(new Error('only positives'))
)
)
# References
Result.catchError
- Chain another operation returning aResult
over anKo
value
# Result.catchError
# Description
Chain another operation returning a Result
over an Ko
value.
<A, E = unknown>(fn: (err: E) => Result<A, E>) => (result: Result<A, E>) => Result<A, E>
# Example
const result: Result<number, Error> = pipe(
Result.ko(Err.of('some error', { name: 'SomeError' })),
Result.catchError(err => pipe(err, Err.hasName('SomeError'))
? Result.ok(1)
: Result.ko(err)
)
)
# References
Result.chain
- Chain another operation returning aResult
over anOk
value
# Result.fold
# Description
Fold over a Result
:
- call
onOk
callback when the value isOk
- call
onKo
callback when the value isKo
<R, A, E = unknown>(onOk: (value: A) => R, onKo: (value: E) => R) => (result: Result<A, E>) => R
# Example
const str = pipe(
Result.ok(1),
Result.fold(
(value) => `Ok = ${value}`,
(err: Error) => `An error occured: ${err.message}`
)
)
expect(str).toBe(`Ok = 1`)
# References
Result.get
# Result.swap
# Description
Swap Ok
and Ko
value
<A, E>(result: Result<A, E>) => Result<E, A>
# Example
const result = pipe(
Result.ok(1),
Result.swap
)
expect(result).toEqual(Result.ko(1))
# Result.tryCatch
# Description
Try/catch an operation. The return value becomes the Ok
, and the thrown value becomes the Ko
<A>(fn: () => A) => Result<A, unknown>
# Example
const divide = (a, b) => b === 0
? throwError(Err.of('cannot divide by zero'))
: a / b
const result = Result.tryCatch(() => divide(1, 0))
# References
Result.fn
# Result.tryCatchFn
# Description
Resultify the given function, making it return a Result
instead of throwing / returning a normal value
<Args extends Array<any>, T>(fun: (...args: Args) => T) => (...args: Args) => Result<T, unknown>
# Example
const divide = (a, b) => b === 0
? throwError(Err.of('cannot divide by zero'))
: a / b
const [ok, ko] = pipe(
[ [1,2], [3,0], [2,3], [4,0] ],
Arr.map(Result.tryCatchFn(([a, b]) => divide(a, b))),
Arr.separate
)
# References
Result.tryCatch
# Result.unionBy
# Description
Takes a list of value as an input.
Applies the function one by one, and returns the first succeeding Result
or all errors
<T, A, E>(fn: (member: T, index: number) => Result<A, E>) => (members: NonEmptyArray<T>) => Result<A, Array<E>>
# Example
const numbers = [-2, -3, 1, -7, -12, -6]
const firstPositive = Result.unionBy(nb => nb >= 0
? Result.ok(nb)
: Result.ko(`${nb} is negative`)
)
expect(pipe([-2, -3, 1, -7, -12], firstPositive)).toBe(1)
expect(pipe([-2, -3, -7, -12], firstPositive)).toEqual([
`-2 is negative`,
`-3 is negative`,
`-7 is negative`,
`-12 is negative`
])
# Result.union
# Description
Returns the first succeeding Result
or all errors
<A, E>(members: NonEmptyArray<Result<A, E>>) => Result<A, Array<E>>
# Example
const results = [Result.ko(`-2 is negative`), Result.ko(`-3 is negative`), Result.ok(1)]
expect(pipe(results, Result.union, Result.get)).toBe(1)
# Result.structBy
# Description
Takes an object of values as an input and applies a function to all properties, to transform each property to a Result
.
If all properties are Ok
, return an Ok
with all values.
If one or more properties are Ko
, return the list of errors.
<T, A, E>(fn: (prop: T, key: string) => Result<A, E>) => (props: any) => Result<any, Array<E>>
# Example
const parseNbs = Result.structBy((prop, key) => {
const nb = parseInt(prop)
return isNaN(nb)
? Result.ko(Err.of(`Invalid number {value} at property {key}`, { value, key }))
: Result.ok(nb)
})
const result1 = pipe(
{
a: "13",
b: "24",
d: "6"
},
parseNbs
)
expect(pipe(result1, Result.get)).toEqual({
a: 13,
b: 24,
d: 6
})
# Result.struct
# Description
Takes an object of results as an input.
If all properties are Ok
, return an Ok
with all values.
If one or more properties are Ko
, return the list of errors.
<T extends any>(props: T) => Result<Struct<T>, Array<StructErrors<T>>>
# Example
const all = pipe(
{
a: Result.ok(13),
b: Result.ok(24),
d: Result.ok(6)
},
Result.struct
)
expect(pipe(all, Result.get)).toEqual({
a: 13,
b: 24,
d: 6
})
← Dictionnary Promise →