Result
Result represents the result of an operation that can either be successful (Ok) or a failure (Error). It's commonly used to represent the result of a function that may fail, such as a network request, a file read, or a database query.
Constructors
ok
Constructs an Ok Result with the provided value.
import { Result } from 'funkcia';
// ββββ Result<number, never>
// βΌ
const result = Result.ok(10);of
Constructs an Ok Result with the provided value.
import { Result } from 'funkcia';
// ββββ Result<number, never>
// βΌ
const result = Result.of(10);error
Constructs an Error result with the provided value.
import { Result } from 'funkcia';
function divide(dividend: number, divisor: number): Result<number, InvalidDivisor> {
if (divisor === 0) {
return Result.error(new InvalidDivisor());
}
return Result.ok(dividend / divisor);
}fromNullable
Constructs a Result from a nullable value.
If the value is null or undefined, it returns a Result.Error with a NoValueError error, or with the value returned by the provided onNullable callback. Otherwise, it returns a Result.Ok.
import { Result } from 'funkcia';
declare const user: User | null;
// ββββ Result<User, NoValueError>
// βΌ
const result = Result.fromNullable(user);
// ββββ Result<string, UserNotFound>
// βΌ
const resultWithCustomError = Result.fromNullable(
user,
() => new UserNotFound(),
);fromFalsy
Constructs a Result from a falsy value.
If the value is falsy, it returns a Result.Error result with a NoValueError error, or with the value returned by the provided onFalsy callback. Otherwise, it returns a Result.Ok.
import { Result } from 'funkcia';
interface User {
id: string;
firstName: string;
lastName: string | null;
}
// ββββ Result<string, NoValueError>
// βΌ
const result = Result.fromFalsy(user.lastName?.trim());
// ββββ Result<string, Error>
// βΌ
const resultWithCustomError = Result.fromFalsy(
user.lastName?.trim(),
() => new Error('User missing last name'),
);try
Constructs a Result from a function that may throw.
If the function executes successfully, it returns a Result.Ok. Otherwise, it returns a Result.Error containing an UnknownError with the thrown exception, or with the value returned by the provided onThrow callback.
import { Result } from 'funkcia';
// ββββ Result<URL, UnknownError>
// βΌ
const url = Result.try(() => new URL('example.com'));
// Output: Error(UnknownError)
// ββββ Result<URL, Error>
// βΌ
const urlWithCustomError = Result.try(
() => new URL('example.com'),
(error) => new Error('Invalid URL'),
);
// Output: Error('Invalid URL')predicate
Returns a function that asserts that a value passes the test implemented by the provided function, creating a Result.Ok, with the value tested, if the predicate is fulfilled.
If the test fails, returns a Result.Error with a FailedPredicateError instead, or with the value returned by the provided onUnfulfilled callback.
import { Result } from 'funkcia';
// With type guard
// ββββ (shape: Shape) => Result
// βΌ
const ensureCircle = Result.predicate(
(shape: Shape): shape is Circle => shape.kind === 'circle',
(shape) => new InvalidShapeError(shape.kind),
);
// With regular predicate
// ββββ (value: number) => Result
// βΌ
const ensurePositive = Result.predicate(
(value: number) => value > 0,
(value) => new InvalidNumberError(value),
);fun
This method improves the inference of the function's return value and guarantees that it will always return a Result. It is extremely useful when your function can return multiple errors.
Declare a function that always returns a Result.
import { Result } from 'funkcia';
// When defining a normal function allowing typescript to infer the return type,
// the return type is always a union of `Result<T, never>` and `Result<never, E>`
function hasAcceptedTermsOfService(user: User) {
if (typeof user.termsOfService !== 'boolean') {
return Result.error('NOT ACCEPTED' as const);
}
return user.termsOfService ?
Result.ok('ACCEPTED' as const)
: Result.error('REJECTED' as cons);
}
// ββββ Result<'ACCEPTED', never> | Result<never, 'REJECTED'> | Result<never, 'NOT ACCEPTED'>
// βΌ
const result = hasAcceptedTermsOfService(user);
// When using the `fun` method, the return type is always `Result<T, E>`
const improvedHasAcceptedTermsOfService = Result.fun(hasAcceptedTermsOfService);
// ββββ Result<'ACCEPTED', 'REJECTED' | 'NOT ACCEPTED'>
// βΌ
const result = improvedHasAcceptedTermsOfService(user);enhance
Converts a function that may throw an exception to a function that returns a Result.
import { Result } from 'funkcia';
// ββββ (text: string, reviver?: Function) => Result<any, TypeError>
// βΌ
const safeJsonParse = Result.enhance(
JSON.parse,
(error) => new TypeError('Invalid JSON'),
);
// ββββ Result<any, TypeError>
// βΌ
const result = safeJsonParse('{ "name": "John Doe" }');
// Output: Ok({ name: 'John Doe' })values
Given an array of Results, returns an array containing only the values inside Result.Ok.
import { Result } from 'funkcia';
// ββββ number[]
// βΌ
const output = Result.values([
Result.ok(1),
Result.error<number>('Failed computation'),
Result.ok(3),
]);
// Output: [1, 3]is
Asserts that an unknown value is a Result.
import { Result } from 'funkcia';
declare const maybeAResultWithUser: unknown;
if (Result.is(maybeAResultWithUser)) {
// ββββ Result<unknown, unknown>
// βΌ
const user = maybeAResultWithUser.filter(isUser);
// β²
// ββββ Result<User, FailedPredicateError<unknown>>
}Instance methods
map
Applies a callback function to the value of the Result when it is Ok, returning a new Result containing the new value.
import { Result } from 'funkcia';
// ββββ Result<number, never>
// βΌ
const result = Result.ok(10).map(number => number * 2);
// Output: Ok(20)mapError
Applies a callback function to the value of the Result when it is Error, returning a new Result containing the new error value.
import { Result } from 'funkcia';
declare const user: User | null;
// ββββ Result<User, UserNotFound>
// βΌ
const result = Result.fromNullable(user).mapError(
(error) => new UserNotFound()
// β²
// ββββ NoValueError
);mapBoth
Maps both the Result value and the Result error to new values.
import { Result } from 'funkcia';
// ββββ Result<string, UserMissingInformationError>
// βΌ
const result = Result.fromNullable(user.lastName).mapBoth({
Ok: (lastName) => `Hello, Mr. ${lastName}`,
Error: (error) => new UserMissingInformationError(),
// β²
// ββββ NoValueError
});andThen
Applies a callback function to the value of the Result when it is Ok, and returns the new value. Similar to chain (also known as flatMap).
import { Result } from 'funkcia';
declare function readFile(path: string): Result<string, FileNotFoundError | FileReadError>;
declare function parseJsonFile(contents: string): Result<FileContent, InvalidJsonError>;
// ββββ Result<FileContent, FileNotFoundError | FileReadError | InvalidJsonError>
// βΌ
const result = readFile('data.json').andThen(parseJsonFile);filter
Asserts that the Result value passes the test implemented by the provided function. Can narrow types and customize error handling.
import { Result } from 'funkcia';
declare const input: Shape;
// ββββ Result<Circle, FailedPredicateError<Square>>
// βΌ
const result = Result.of(input).filter(
(shape): shape is Circle => shape.kind === 'CIRCLE',
);
// ββββ Result<Circle, Error>
// βΌ
const resultWithCustomError = Result.of(input).filter(
(shape): shape is Circle => shape.kind === 'CIRCLE',
(shape) => new Error(`Expected Circle, received ${shape.kind}`),
// β²
// ββββ Square
);or
Replaces the current Result with the provided fallback Result when it is Error.
import { Result } from 'funkcia';
const personalEmail = Result.ok('[email protected]')
.or(() => Result.ok('[email protected]'))
.unwrap();
// Output: '[email protected]'
const workEmail = Result.error(new Error('Missing personal email'))
.or(() => Result.ok('[email protected]'))
.unwrap();
// Output: '[email protected]'swap
Swaps the Result value and error. If Ok, returns Error with the value. If Error, returns Ok with the error.
import { Result } from 'funkcia';
declare function getCachedUser(email: Email): Result<User, CacheMissError<Email>>;
declare function findOrCreateUserByEmail(email: Email): User;
// ββββ Result<User, User>
// βΌ
const result = getCachedUser('[email protected]')
.swap() // Result<CacheMissError<Email>, User>
.map((cacheMiss) => findOrCreateUserByEmail(cacheMiss.input));
// β²
// ββββ CacheMissError<Email>zip
Combines two Results into a single Result containing a tuple of their values, if both Results are Ok variants, otherwise, returns Result.Error.
import { Result } from 'funkcia';
const first = Result.some('hello');
const second = Result.some('world');
// ββββ Result<[string, string], never>
// βΌ
const strings = first.zip(second);
// Output: Ok(['hello', 'world'])zipWith
Combines two Results into a single Result. The new value is produced by applying the given function to both values, if both Results are Ok variants, otherwise, returns Error.
import { Result } from 'funkcia';
const first = Result.some('hello');
const second = Result.some('world');
// ββββ Result<string, never>
// βΌ
const greeting = first.zipWith(second, (a, b) => `${a} ${b}`);
// Output: Ok('hello world')match
Compare the Result against the possible patterns and then execute code based on which pattern matches.
import { Result } from 'funkcia';
declare function readFile(path: string): Result<string, FileNotFoundError | FileReadError>;
declare function parseSalesRecords(content: string): Result<SalesRecord[], InvalidSalesRecordFileError>;
declare function aggregateSales(salesRecords: SalesRecord[]): AggregatedSaleRecord[];
// ββββ AggregatedSaleRecord[]
// βΌ
const data = readFile('data.json')
.andThen(parseSalesRecords)
.match({
Ok(contents) {
return aggregateSales(contents);
},
// ββββ FileNotFoundError | FileReadError | InvalidSalesRecordFileError
// βΌ
Error(error) {
return []
},
});unwrap
Throws UnwrapError if the Result is Error.
Unwraps the Result value.
import { Result } from 'funkcia';
// ββββ number
// βΌ
const number = Result.ok(10).unwrap();
Result.error(new Error('Β―\_(γ)_/Β―')).unwrap();
// Output: Uncaught exception: 'called "Result.unwrap()" on an "Error" value'unwrapError
Throws UnwrapError if the Result is Ok.
Unwraps the Result error.
import { Result } from 'funkcia';
const result = Result.error(new UserNotFound());
if (result.isError()) {
const error = result.unwrapError();
// β²
// ββββ UserNotFound
}unwrapOr
Returns the value of the Result. If the Result is Error, returns the fallback value.
import { Result } from 'funkcia';
// ββββ string
// βΌ
const baseUrl = Result.ok('https://funkcia.lukemorales.io')
.unwrapOr(() => 'http://localhost:3000');
// Output: 'https://funkcia.lukemorales.io'
const apiKey = Result.error('Missing API key')
.unwrapOr(() => 'sk_test_9FK7CiUnKaU');
// Output: 'sk_test_9FK7CiUnKaU'unwrapOrNull
Unwraps the value of the Result if it is a Ok, otherwise returns null.
import { Result } from 'funkcia';
declare const findUserById: (id: string) => Result<User, UserNotFound>;
// ββββ User | null
// βΌ
const user = findUserById('user_123').unwrapOrNull();unwrapOrUndefined
Unwraps the value of the Result if it is a Ok, otherwise returns undefined.
import { Result } from 'funkcia';
declare const findUserById: (id: string) => Result<User, UserNotFound>;
// ββββ User | undefined
// βΌ
const user = findUserById('user_123').unwrapOrUndefined();expect
Throws the provided Error if the Result is Error.
Unwraps the Result value.
import { Result } from 'funkcia';
declare function findUserById(id: string): Result<User, NoValueError>;
// ββββ User
// βΌ
const user = findUserById(userId).expect(
(error) => new UserNotFound(userId)
// β²
// ββββ NoValueError
);merge
Returns the value inside the Result. If Ok, returns the value; if Error, returns the error.
import { Result } from 'funkcia';
declare function getCachedUser(email: Email): Result<User, CacheMissError<Email>>;
declare function getOrCreateUserByEmail(email: Email): User;
// ββββ User
// βΌ
const result = getCachedUser('[email protected]')
.swap() // Result<CacheMissError<Email>, User>
.map((cacheMiss) => getOrCreateUserByEmail(cacheMiss.input)) // Result<User, User>
.merge();
// Output: { id: 'user_123', email: '[email protected]' }contains
Returns true if the predicate is fulfilled by the wrapped value. If the predicate is not fulfilled or the Result is Error, it returns false.
import { Result } from 'funkcia';
// ββββ boolean
// βΌ
const isPositive = Result.ok(10).contains(num => num > 0);
// Output: true
const isNegative = Result.error(10).contains(num => num < 0);
// Output: falsetoArray
Converts a Result to an array. If Result is Ok, returns an array with the value. If Result is Error, returns an empty array.
import { Result } from 'funkcia';
// ββββ number[]
// βΌ
const output = Result.ok(10).toArray();
// Output: [10]toOption
Converts a Result to an Option. If Result is Ok, returns an Option.Some. If Result is Error, returns an Option.None.
import { Result } from 'funkcia';
declare function readFile(path: string): Result<string, FileNotFoundError | FileReadError>;
declare function parseSalesRecords(content: string): Result<SalesRecord[], InvalidSalesRecordFileError>;
// ββββ Option<SalesRecord[]>
// βΌ
const fileContents = readFile('data.json')
.andThen(parseSalesRecords)
.toOption();toAsyncOption
Converts the Result to an AsyncOption.
import { Result } from 'funkcia';
declare function readFile(path: string): Result<string, FileNotFoundError | FileReadError>;
declare function parseSalesRecords(content: string): Result<SalesRecord[], InvalidSalesRecordFileError>;
// ββββ AsyncOption<SalesRecord[]>
// βΌ
const asyncFile = readFile('data.json')
.andThen(parseSalesRecords)
.toAsyncOption();
// Output: Promise<Some(SalesRecord[])>toAsyncResult
Converts the Result to an AsyncResult.
import { Result } from 'funkcia';
declare function readFile(path: string): Result<string, FileNotFoundError | FileReadError>;
declare function parseSalesRecords(content: string): Result<SalesRecord[], InvalidSalesRecordFileError>;
// ββββ AsyncResult<SalesRecord[], FileNotFoundError | FileReadError | InvalidSalesRecordFileError>
// βΌ
const asyncFile = readFile('data.json')
.andThen(parseSalesRecords)
.toAsyncResult();
// Output: Promise<Ok(SalesRecord[])>tap
Calls the function with the Result value, then returns the Result itself, ignoring the returned value of the provided function.
This allows "tapping into" a function sequence in a pipe, to perform side effects on intermediate results.
import { Result } from 'funkcia';
// ββββ Result<number, never>
// βΌ
const result = Result.some(10).tap(
(value) => console.log(value), // Console output: 10
);tapError
Calls the function with the Result error, then returns the Result itself, ignoring the returned value of the provided function.
This allows "tapping into" a function sequence in a pipe, to perform side effects on intermediate results.
import { Result } from 'funkcia';
declare function findUserById(id: string): Result<User, UserNotFound>;
// ββββ Result<User, UserNotFound>
// βΌ
const result = findUserById('invalid_id').tapError(
(error) => console.log(error), // Console output: UserNotFound
);isOk
Returns true if the Result contains a value.
import { Option } from 'funkcia';
declare function findUserById(id: string): Result<User, UserNotFound>;
const user = findUserById('user_123');
if (user.isOk()) {
return user.unwrap(); // `unwrap` will not throw
}isError
Returns true if the Result contains an error.
import { Option } from 'funkcia';
declare function findUserById(id: string): Result<User, UserNotFound>;
const user = findUserById('invalid_id');
if (user.isError()) {
const error = user.unwrapError(); // `unwrapError` will not throw
// ...process error
}
return user.unwrap();equals
Compares the Result with another Result and returns true if they are equal.
import { Result } from 'funkcia';
const result = Result.of(10).equals(Result.ok(10));
// Output: trueLast updated
Was this helpful?