Whats wrong with typescript control flow?
The native support for Errors, and optional values in typescript/javascript is very limited and presents bad patterns. Not all errors are unexpected, an error can often represent a deviation from the happy-path rather than some panic. However, using errors to represent these states and having them thrown throughout your code means implicit control flow. Typescript also cannot infer the thrown types so an end user has no way of knowing the possible errors thrown by a function without digging through all of the source code. Languages that support algebraic sum types commonly encourage a pattern of a union Success/Error type that makes clear what are the success and fail states throughout the code.
For example lets compare idiomatic Rust and Typescript side by side.
When using this function the user has no idea that a value could be thrown because the return type is number
. Compare this to rust where the state transitions are much more explicit.
In this code is clear that the returning type is either no value or a ParseIntError
. This pattern also makes for really clean code patterns as monadic types like this usually are functors that can chain operations only applying when valid.
These patterns are incredible for writing reliable and understandable code.
Introducing Outcomes
Outcomes is a typescript library to more explicitly handle common control flow operations. Outcomes implements the Result
and Option
types to make dealing with error and null states a breeze. To get started install the package from the JSR Package Repository. The Outcomes library implements common functor operations for Result
and Option
types as well as the shorthand constructors for the returnable union types.
Explicit Error Handling
Lets look at example of error handling.
Results are either Ok
or an Err
to represent the valid states. You can see that you can still use the standard javascript Error
class if you wish, or create your own error types. Maybe your function has multiple possible known errors - create a union! The types are irrelevant because the Result
wraps your values in a tagged union.
Nullable values can be improved
You can also use Option
types to represent nullable values.
This might not seem as necessary because of first class optional chaining in typescript but having a clear None
type enables more functionality than just spamming optional chaining and nullish coalescing operators.
Going forward
The full documentation can be found with the package on the JSR Package Repository.
I will be implementing more features soon primarily for dealing with arrays and async values.