The Resulting package provides a Result
class designed to handle success and failure scenarios in a functional programming style. It encapsulates a
result,
which can either be a Success
with a value or a Failure
with an error, offering methods to safely operate on these results. This type is based on
the Kotlin
Result
type.
To install the dependencies, use npm or yarn:
npm install @felipearpa/resulting
Or if you’re using yarn:
yarn install @felipearpa/resulting
Here’s how you can use the package after installation. You can import the package and use its features like this:
import { Result } from '@felipearpa/resulting';
const successFailure = Result.success('success result');
console.log(successResult.isSuccess); // Output: true
console.log(successResult.isFailure); // Output: false
const failureResult = Result.failure(Error('error result'));
console.log(failureResult.isFailure); // Output: true
console.log(failureResult.isSuccess); // Output: false
To run tests, use:
npm run test
Jest will automatically detect all test files and run them. For more advanced testing, refer to the Jest documentation.
If you would like to contribute, please open a pull request or submit an issue. We are happy to review your changes or ideas!.
This project is licensed under the MIT License. You are free to use, modify, and distribute this software for both personal and commercial use. There are no restrictions on usage.
You can now add this section to your README.md to reflect that the project is open source and free to use. Let me know if you’d like to include additional details!.
Result<Value>
A discriminated union that encapsulates a successful outcome with a value of type Value or a failure with an arbitrary error.
static success(value: Value)
Returns an instance that encapsulates the given value as successful value.
import { Result } from '@felipearpa/resulting';
const result = Result.success('action succeeded');
static failure(error: Error)
Returns an instance that encapsulates the given error as failure.
import { Result } from '@felipearpa/resulting';
const result: Result<string> = Result.failure(Error('action failed'));
isSuccess: boolean
Returns true if this instance represents a successful outcome. In this case isFailure returns false.
import { Result } from '@felipearpa/resulting';
const result = Result.success('action succeeded');
if (result.isSuccess) {
console.log('action succeeded with value: ', result.getOrNull()); // Output: action succeeded with value: action succeeded
} else {
console.error('action failed with error: ', result.errorOrNull());
}
isFailure: boolean
Returns true if this instance represents a failed outcome. In this case isSuccess returns false.
import { Result } from '@felipearpa/resulting';
const result: Result<string> = Result.failure(Error('action failed'));
if (result.isSuccess) {
console.log('action succeeded with value: ', result.getOrNull());
} else {
console.error('action failed with error: ', result.errorOrNull()); // Output: action failed with error: action failed
}
getOrNull(): Value | null
Returns the encapsulated value if this instance represents success or null if it is failure.
import { Result } from '@felipearpa/resulting';
const result = Result.success('action succeeded');
const valueOrNull = result.getOrNull();
if (valueOrNull !== null) {
console.log('action succeeded with value: ', valueOrNull); // Output: action succeeded with value: action succeeded
} else {
console.log('action failed, no value available');
}
getOrThrow(): Value
Returns the encapsulated value if this instance represents success or throws the encapsulated error if it is failure.
import { Result } from '@felipearpa/resulting';
const result = Result.success('action succeeded');
try {
const value = result.getOrThrow();
console.log('action succeeded with value: ', value); // Output: action succeeded with value: action succeeded
} catch (error) {
console.error('action failed with error: ', error.message);
}
import { Result } from '@felipearpa/resulting';
const result = Result.failure('action failed');
try {
const value = result.getOrThrow();
console.log('action succeeded with value: ', value);
} catch (error) {
console.error('action failed with error: ', error.message); // Output: action failed with error: action failed
}
getOrDefault(defaultValue: Value): Value
Returns the encapsulated value if this instance represents success or the defaultValue if it is failure.
import { Result } from '@felipearpa/resulting';
const result: Result<string> = Result.failure(Error('action failed'));
const value = result.getOrDefault('default value');
console.log('Result: ', value); // Output: default value
getOrElse<NewValue, Value extends NewValue>(this: Result<Value>, onFailure: (error: Error) => NewValue): NewValue
Returns the encapsulated value if this instance represents success or the result of onFailure function for the encapsulated Error if it is failure.
import { Result } from '@felipearpa/resulting';
const result: Result<string> = Result.failure(Error('action failed'));
const value = result.getOrElse((error) => {
console.error('error occurred: ', error.message);
return 'fallback value';
});
console.log('Result: ', value); // Output: fallback value
errorOrNull(): Error | null
Returns the encapsulated error if this instance represents failure or null if it is success.
import { Result } from '@felipearpa/reesult';
const result: Result<string> = Result.failure(Error('action failed'));
const error = result.errorOrNull();
if (error !== null) {
console.error('action failed with error: ', error.message); // Output: action failed with error: action failed
} else {
console.log('action succeeded');
}
map<NewValue>(transform: (value: Value) => NewValue): Result<NewValue>
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.success(10);
const transformedResult = result.map(value => value * 2);
if (transformedResult.isSuccess) {
console.log('transformed value: ', transformedResult.getOrThrow()); // Output: transformed value: 20
} else {
console.error('action failed');
}
fold<NewValue>(onSuccess: (value: Value) => NewValue, onFailure: (error: Error) => NewValue): NewValue
fold<NewValue>(handlers: { onSuccess: (value: Value) => NewValue, onFailure: (error: Error) => NewValue }): NewValue
Returns the result of onSuccess for the encapsulated value if this instance represents success or the result of onFailure function for the encapsulated error if it is failure.
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.success(42);
const transformedResult = result.fold(
value => `Success! The value is ${value}`,
error => `Failure! The error is: ${error.message}`
);
console.log(transformedResult); // Output: Success! The value is: 42
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.success(42);
const transformedResult = result.fold({
onSuccess: (value) => `Success! The value is ${value}`,
onFailure: (error) => `Failure! The error is: ${error.message}`
});
console.log(transformedResult); // Output: Success! The value is: 42
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.failure(Error('action failed'));
const transformedResult = result.fold(
value => `Success! The value is ${value}`,
error => `Failure! The error is: ${error.message}`
);
console.log(transformedResult); // Output: Failure! The error is: action failed
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.failure(Error('action failed'));
const transformedResult = result.fold({
onSuccess: (value) => `Success! The value is ${value}`,
onFailure: (error) => `Failure! The error is: ${error.message}`
});
console.log(transformedResult); // Output: Failure! The error is: action failed
recover<NewValue, Value extends NewValue>(this: Result<Value>, transform: (error: Error) => NewValue): Result<NewValue>
Returns the encapsulated result of the given transform function applied to the encapsulated error if this instance represents failure or the original encapsulated value if it is success.
import { Result } from '@felipearpa/resulting';
const result: Result<number> = Result.failure(Error('action failed'));
const recoveredResult = result.recover(error => {
console.error('Recovering from error:', error.message);
return 100; // Providing a fallback value
});
if (recoveredResult.isSuccess) {
console.log('Recovered value: ', recoveredResult.getOrThrow()); // Output: Recovered value: 100
} else {
console.error('Recovery failed');
}
onSuccess(action: (value: Value) => void): Result<Value>
Performs the given action on the encapsulated value if this instance represents success. Returns the original Result unchanged.
import { Result } from '@felipearpa/resulting';
const result = Result.success('action succeeded');
result.onSuccess(value => {
console.log('action succeeded with value: ', value); // Output: Operation succeeded with value: action succeeded
});
onFailure(action: (error: Error) => void): Result<Value>
Performs the given action on the encapsulated Throwable exception if this instance represents failure. Returns the original Result unchanged.
import { Result } from '@felipearpa/resulting';
const result: Result<string> = Result.failure(Error('action failed'));
result.onFailure(error => {
console.error('action failed with error:', error.message); // Output: action failed with error: action failed
});
toString(): string
Returns a string Success(v) if this instance represents success where v is a string representation of the value or a string Failure(x) if it is failure where x is a string representation of the error.
import { Result } from '@felipearpa/resulting';
const successResult = Result.success('action succeeded');
const failureResult: Result<string> = Result.failure(Error('action failed'));
console.log(successResult.toString()); // Output: Success(action succeded)
console.log(failureResult.toString()); // Output: Failure(action failed)
mapCatching<NewValue>(transform: (value: Value) => NewValue): Result<NewValue>
Returns the encapsulated result of the given transform function applied to the encapsulated value if this instance represents success or the original encapsulated error if it is failure.
import { Result, runCatching } from '@felipearpa/resulting';
const result: Result<number> = Result.success(10);
const transformedResult = result.mapCatching(value => {
if (value < 0) {
throw Error('negative value');
}
return value * 2;
});
if (transformedResult.isSuccess) {
console.log('transformed value: ', transformedResult.getOrThrow()); // Output: transformed value: 20
} else {
console.error('transformation failed with error: ', transformedResult.errorOrNull()?.message);
}
import { Result, runCatching } from '@felipearpa/resulting';
const result: Result<number> = Result.success(-10);
const transformedResult = result.mapCatching(value => {
if (value < 0) {
throw Error('negative value');
}
return value * 2;
});
if (transformedResult.isSuccess) {
console.log('transformed value: ', transformedResult.getOrThrow());
} else {
console.error('transformation failed with error: ', transformedResult.errorOrNull()?.message); // Output: transformation failed with error: negative value
}
recoverCatching<NewValue>(transform: (error: Error) => NewValue): Result<NewValue>
Returns the encapsulated result of the given transform function applied to the encapsulated error if this instance represents failure or the original encapsulated value if it is success.
import { Result, runCatching } from '@felipearpa/resulting';
const result: Result<number> = Result.failure(new Error('initial failure'));
const recoveredResult = result.recoverCatching(error => {
if (error.message === 'initial failure') {
throw new Error('recovery failed'); // Simulate a failure during recovery
}
return 42; // Recover with a fallback value
});
if (recoveredResult.isSuccess) {
console.log('recovered value: ', recoveredResult.getOrThrow());
} else {
console.error('recovery failed with error: ', recoveredResult.errorOrNull()?.message); // Output: recovery failed with error: recovery failed
}
import { Result, runCatching } from '@felipearpa/resulting';
const result: Result<number> = Result.failure(new Error('final failure'));
const recoveredResult = result.recoverCatching(error => {
if (error.message === 'initial failure') {
throw new Error('recovery failed'); // Simulate a failure during recovery
}
return 42; // Recover with a fallback value
});
if (recoveredResult.isSuccess) {
console.log('recovered value: ', recoveredResult.getOrThrow()); // Output: recovered value: 42
} else {
console.error('recovery failed with error: ', recoveredResult.errorOrNull()?.message);
}
const runCatching = <Value>(block: () => Value): Result<Value>
Calls the specified function block and returns its encapsulated result if invocation was successful, catching any error that was thrown from the block function execution and encapsulating it as a failure.
import { Result, runCatching } from '@felipearpa/resulting';
function riskyOperation(): string {
if (Math.random() > 0.5) {
throw Error('something went wrong');
}
return 'action succeeded';
}
const result: Result<string> = runCatching(() => riskyOperation());
if (result.isSuccess) {
console.log('Success:', result.getOrThrow()); // If successful, log the value
} else {
console.error('Failure:', result.errorOrNull()?.message); // If failure, log the error
}