Scenario's API is subject to change.
Please check back later to see the improvements. And note that this Readme currently acts as the official and only set of documentation.
Please open an issue if you want to
- request a feature
- request documentation clarification
- report a bug
Scenario is a Result and Option type library that lets you safely handle potential failures and abscense of values within you JavaScript or TypeScript application.
Scenario has 0 dependencies and is very small (less than 1kb!).
Scenario is useful for both TypeScript and JavaScript projects because of its runtime functionality and semantics.
npm add @keeoth/scenario
yarn add @keeoth/scenario
pnpm add @keeoth/scenario
Please explore the API Reference at Stackblitz for a full picture of the library and usage (work in progress!).
Scenario's Option and Result types will help you avoid being in unexpected situations like accessing values that don't exist (or shouldn't exist) or treating some computation's result as a success when it really is a failure.
A lot of similar projects offer their Result or Option type as a type alias for a TypeScript union. Something like this:
type Result<T, U> = Success<T> | Failure<U>
type Option<V> = Some<V> | None
This strategy has the unfortunate drawback that Intellisense isn't guaranteed to show you the type alias – which can lead to noisy types.
I.e. you may often see
Success<MySuccessType> | Failure<MyFailureType>
// and
Some<MySomeType> | None
instead of
Result<MySuccessType, MyFailureType>
// and
Option<MySomeType>
Scenario's Result and Option types are JavaScript classes so they have runtime semantics. This means you'll always see the more concise typing of
Result<MySuccessType, MyFailureType>
// and
Option<MySomeType>
For best ergonomics and typing, please ensure that your tsconfig.json
file has these settings:
{
"compilerOptions": {
"strict": true,
"strictNullChecks": true
}
}
An Option represent the potential abscense of a value. They provide safe ways for you to access and operate on these potentially absent values.
An Option representing a guaranteed value is called a Some. An Option representing an absent value is called a None.
Please see the source code and test files for further documentation usage examples.
// Options.from will be a Some if the passed in
// value is anything but `undefined` or `null`.
// Otherwise, it will be a None.
const option = Option.from(0) // `option` is a Some
// or Option.some(0)
const newOption = option.map((value) => value + 10)
// Check if newOption is a Some
newOption.isSome() // true
// Check if newOption is a None
newOption.isNone() // false
// In case of a Some, retrieve the value.
// Otherwise, in case of a None, retrieve
// the fallback (`20`).
newOption.valueOr(20) // 10
// In case of a Some, retrieve the value.
// Otherwise, in case of a None, retrieve
// the result of the passed in function.
newOption.valueOr(() => 20) // 10
const option = Option.from(null) // `option` is a Nome
// or Option.none()
const newOption = option.map((value) => value + 10)
newOption.isSome() // false
// Check if newOption is a None
newOption.isNone() // true
// In case of a Some, retrieve the value.
// Otherwise, in case of a None, retrieve
// the fallback (`20`).
newOption.valueOr(20) // 20
// In case of a Some, retrieve the value.
// Otherwise, in case of a None, retrieve
// the result of the passed in function.
newOption.valueOr(() => 20) // 20
const getFirstItem = <T>(items: T[]): Option<T> => {
const [firstItem] = items
return Option.from(firstItem)
}
getFirstItem([]) // None
getFirstItem([1]) // Some
An Result represent the potential success or failure of an operation. They provide safe ways for you to access and operate on these potentially absent values.
A Result representing a success is called a Success. A Result representing a failure is called a Failure.
Please see the source code and test files for further documentation usage examples.
// Results.success will create a Success
// no matter what value you pass to it.
const result = Result.success(0) // `result` is a Success
// or Result.some(0)
const newResult = result.map((value) => value + 10)
// Check if newResult is a Success
newResult.isSuccess() // true
// Check if newResult is a None
newResult.isFailure() // false
// In case of a Success, retrieve the value.
// Otherwise, in case of a Failure, retrieve
// the fallback (`20`).
newResult.valueOr(20) // 10
// In case of a Success, retrieve the value.
// Otherwise, in case of a Failure, retrieve
// the result of the passed in function.
newResult.valueOrCompute(() => 20) // 10
// Results.failure will create a Failure
// no matter what value you pass to it.
const result = Result.failure('SOME_FAILURE') // `result` is a Failure
const newResult = result.map((value) => value + 10)
newResult.isSuccess() // false
// Check if newResult is a Failure
newResult.isFailure() // true
// In case of a Success, retrieve the value.
// Otherwise, in case of a Failure, retrieve
// the fallback (`20`).
newResult.valueOr(20) // 20
// In case of a Success, retrieve the value.
// Otherwise, in case of a Failure, retrieve
// the result of the passed in function.
newResult.valueOrCompute(() => 20) // 20
type FailureMessage = string
const getFirstItem = <T>(items: T[]): Result<T, FailureMessage> => {
const [firstItem] = items
if (firstItem) {
return Result.success(firstItem)
}
return Result.failure('UNABLE_TO_FIND_FIRST_ITEM')
}
const failureResult = getFirstItem([])
failureResult.value() // "UNABLE_TO_FIND_FIRST_ITEM"
const successResult = getFirstItem([1]) // Success
successResult.value() // 1