result-library
v1.1.4
Published
A TypeScript utility for handling success (Ok) and failure (Err) cases in a structured and type-safe manner.
Maintainers
Readme
Result Library
The Result library is a TypeScript utility that provides a structured way to handle success (Ok) and failure (Err) cases in your application. It is inspired by functional programming patterns and languages like Rust, enabling robust error handling without relying on exceptions.
Features
- Type Safety: Explicitly handle
OkandErrcases with strong TypeScript typings. - Convenient API: Simplifies handling success and error scenarios with intuitive methods.
- Improved Error Handling: Avoid unexpected runtime errors with structured control flows.
- Reusable Components: Easily integrate into any TypeScript project.
Installation
npm install result-libraryUsage
Simpler Version
import { Err, Ok, type Result } from 'result-library'
function maybeNumber(success: boolean): Result<number, string> {
if(success) return new Ok(1)
return new Err("it failed")
}
maybeNumber(true).unwrap() // 1
maybeNumber(false).unwrap_err() // "it failed"Creating Results
To create Ok and Err results, use the ResultBuilder interface.
import { ResultBuilder } from 'result-library';
const { Ok, Err } = ResultBuilder<string, string>();
const success = Ok("Operation was successful");
const failure = Err("An error occurred");Checking Results
if (success.is_ok()) {
console.log("Success:", success.unwrap());
} else {
console.error("Error:", success.err());
}
if (failure.is_err()) {
console.error("Failure:", failure.unwrap_err());
}Example Use Case
function divide(a: number, b: number) {
const { Ok, Err } = ResultBuilder<number, string>();
if (b === 0) {
return Err("Division by zero is not allowed");
}
return Ok(a / b);
}
const result = divide(10, 2);
if (result.is_ok()) {
console.log("Result:", result.unwrap());
} else {
console.error("Error:", result.unwrap_err());
}Advanced Usage with Types
You can define explicit types for better type safety.
const { Ok, Err } = ResultBuilder<number, string>();
const result = Ok(42);
const error = Err("Something went wrong");
if (result.is_ok()) {
console.log(result.unwrap());
} else {
console.error(result.unwrap_err());
}Additional Example: Handling Multiple Cases
function fetchUserData(userId: string) {
const { Ok, Err } = ResultBuilder<{ name: string; age: number }, string>();
if (userId === "123") {
return Ok({ name: "John Doe", age: 30 });
} else {
return Err("User not found");
}
}
const userResult = fetchUserData("123");
if (userResult.is_ok()) {
console.log("User Data:", userResult.unwrap());
} else {
console.error("Error:", userResult.unwrap_err());
}Use Case: File Processing
function processFile(filePath: string) {
const { Ok, Err } = ResultBuilder<string, string>();
if (!filePath.endsWith(".txt")) {
return Err("Only .txt files are supported");
}
try {
const fileContent = "File content"; // Simulate reading a file
return Ok(fileContent);
} catch (error) {
return Err("Failed to process the file");
}
}
const fileResult = processFile("example.txt");
if (fileResult.is_ok()) {
console.log("File Content:", fileResult.unwrap());
} else {
console.error("Error:", fileResult.unwrap_err());
}Use Case: API Response Handling
async function fetchData(apiUrl: string) {
const { Ok, Err } = ResultBuilder<any, string>();
try {
const response = await fetch(apiUrl);
if (!response.ok) {
return Err(`API error: ${response.status}`);
}
const data = await response.json();
return Ok(data);
} catch (error) {
return Err("Network error");
}
}
(async () => {
const apiResult = await fetchData("https://api.example.com/data");
if (apiResult.is_ok()) {
console.log("API Data:", apiResult.unwrap());
} else {
console.error("Error:", apiResult.unwrap_err());
}
})();The Result class provides a way to handle success and error outcomes in a structured way. Below is an example demonstrating how to use Ok, Err, and the ResultBuilder to handle different results.
Code Example:
import { ResultBuilder } from 'result-library';
// deconstruct ResultBuilder and create Ok, Err builder instance
const { Ok, Err } = ResultBuilder<string, string>();
// Simulate a function that can either succeed or fail
function fetchData(success: boolean) {
if (success) {
return Ok('Data retrieved successfully');
} else {
return Err('Failed to retrieve data');
}
}
// Simulate a success scenario
const successResult = fetchData(true);
if (successResult.is_ok()) {
console.log(successResult.ok()); // Output: 'Data retrieved successfully'
} else {
console.log(successResult.err());
}
// Simulate an error scenario
const errorResult = fetchData(false);
if (errorResult.is_err()) {
console.log(errorResult.err()); // Output: 'Failed to retrieve data'
} else {
console.log(errorResult.ok());
}
try {
console.log(successResult.unwrap()); // Output: 'Data retrieved successfully'
console.log(errorResult.unwrap()); // Throws error: "Called unwrap() on an Ok value"
} catch (e) {
console.error(e.message);
}
try {
console.log(successResult.unwrap_err()); // Throws error: "Called unwrap_err() on an Ok value"
} catch (e) {
console.error(e.message);
}Helper Methods Examples
These helpers make control flow expressive while remaining type-safe.
import { Ok, Err, type Result } from 'result-library';
// andThen: chain computations if Ok, otherwise propagate Err
const doubleIfOk: Result<number, string> = new Ok<number, string>(2)
.andThen((n) => new Ok<number, string>(n * 2)); // Ok(4)
// orElse: recover from Err, pass through Ok unchanged
const recoverFromErr: Result<number, number> = new Err<string, number>('nope')
.orElse((e) => new Err<number, number>(e.length)); // Err(4)
// expect / expectErr: unwrap with custom error messages
new Ok<number, string>(7).expect('should be ok'); // 7
// throws: Error('must be an error')
new Ok<number, string>(7).expectErr('must be an error');
// tap / tapErr: side-effects without changing the Result
let seenOk: number | undefined;
let seenErr: string | undefined;
new Ok<number, string>(3).tap((n) => { seenOk = n; }); // seenOk = 3
new Err<string, number>('bad').tapErr((e) => { seenErr = e; }); // seenErr = 'bad'Advantages
- Eliminates Ambiguity: Clear distinction between success and error states.
- Improves Readability: Code is more declarative and self-documenting.
- Avoids Exceptions: Encourages error handling through return types instead of exceptions.
- Enhances Debugging: Easily identify and manage error cases.
API Reference
Result<A, E>
A generic class representing either a success (Ok) or failure (Err) value.
Methods:
is_ok(): boolean: Returnstrueif the result isOk.is_err(): boolean: Returnstrueif the result isErr.ok(): A: Retrieves the success value.err(): E: Retrieves the error value.unwrap(): A: Returns the success value or throws an error if the result isErr.unwrap_err(): E: Returns the error value or throws an error if the result isOk.unwrapErr(): E: CamelCase alias forunwrap_err().when<R>({ ok, err }): R: Branch onOk/Errand returnR.fold<R>({ ok, err }): Promise<R>: Async-friendly branching; handlers may returnRorPromise<R>.map<RT>(mapper): Result<RT, E>: Map theOkartifact.mapErr<RE>(mapper): Result<A, RE>: Map theErrerror.mapOr<RT>(mapper, defaultValue): RT: Map theOkartifact, otherwise returndefaultValue.mapOrElse<RT>(mapper, errMapper): RT: Map theOkartifact, otherwise compute from error.mapOrErr<RE>(mapper, defaultValue): RE: OnOk, returndefaultValue; onErr, map the error.mapErrOr<RT>(mapper, defaultValue): RT: OnOk, returndefaultValue; onErr, map the error toRT.mapErrOrElse<T>(mapper, defaultValue): T: OnOk, returndefaultValue; onErr, map error toT.unwrapOr(defaultValue): A: Return the artifact ordefaultValue.unwrapOrElse(defaultValue): A: Return the artifact or compute it from error.andThen<RT>(fn): Result<RT, E>: IfOk, callfn(artifact)and return its Result; ifErr, propagate.orElse<RE>(fn): Result<A, RE>: IfErr, callfn(error)and return its Result; ifOk, propagate.expect(message): A: UnwrapOkor throwError(message)ifErr.expectErr(message): E: UnwrapError throwError(message)ifOk.tap(fn): Result<A, E>: Runfn(artifact)whenOk; return original Result.tapErr(fn): Result<A, E>: Runfn(error)whenErr; return original Result.
Ok<A, E>
A subclass of Result representing a success state.
Err<E, A>
A subclass of Result representing an error state.
ResultBuilder
An interface for creating Ok and Err instances.
Ok<A, E>(value: A): Ok<A, E>: Creates anOkresult with the given value.Err<E, A>(error: E): Err<E, A>: Creates anErrresult with the given error.
Contributing
Contributions are welcome! Please open an issue or submit a pull request for enhancements or bug fixes.
License
This library is licensed under the MIT License. See LICENSE for details.
