Created Result Type in TypeScript
hirohata
Posted on November 15, 2023
I created my result type. Repository / NPM
Motivation
Handling errors is a crucial aspect of creating reliable and readable code. While TypeScript (JavaScript) offers a try-catch syntax, it can be challenging to clearly recognize whether a function returns an error or not.
By using the Result type, we can explicitly express that a function has the potential to return an error.
In a recent personal project I joined, we opted for TypeScript. Consequently, we chose to implement and utilize the following Result type:
type Result<T, E> = {
ok: true,
value: V
} | {
ok: false,
error: E
}
const Ok = <T, E>(value: V): Result<T, E> => ({ ok: true, value });
const Err = <T, E>(error: E): Result<T, E> => ({ ok: false, error });
It works well in the code. We can explicitly express that a function may return an error state, allowing us to handle errors without using try-catch.
const result: Result<T, E> = someFunction();
if (result.ok) {
// this result is inferred to the OK.
// do something
} else {
// this result is error.
// do error handling.
}
However, this result type resulted in pain in testing.
When writing tests, there are instances where we need to create dummy objects convincing an 'OK' type. In such cases, we found ourselves needing to check if the result is 'OK' or 'Err' using an if-condition. If we attempt to access the value without checking the 'ok' field in the result type, the IDE raises a warning. This can be quite bothersome and affects code readability.
let okValue;
const result = someFunction();
if (result.ok) {
okValue = result.value;
} else {
// this is used in tests, so we don't need error handling.
throw new Error("error message")
}
Created Result Type
To address this situation, I created my result type.
export type Result<T, E> = IOk<T> | IErr<E>;
interface IOk<T> {
ok: true;
value: T;
unwrap(): T;
unwrapOrElse(defaultValue: T): T;
unwrapError(): never;
}
interface IErr<E> {
ok: false;
error: E;
unwrap(): never;
unwrapOrElse(DefaultValue: any): any;
unwrapError(): E;
}
This key feature of this result type is an implementation of the unwrap
method, inspired by Rust's approach. With this method, there is no longer a need to explicitly check the 'ok' field.
const okValue = someFunction().unwrap();
This result type significantly streamlines our development process.
Conclusion
The use of result type in TypeScript is a subject of much debate, and various packages have been created. In our specific use case, the result type I created meets our requirements satisfactorily at least.
I want to use Rust. 🦀🦀🦀
Posted on November 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.