DEV Community

Cover image for Created Result Type in TypeScript
hirohata
hirohata

Posted on • Edited on

7 2 2 2 2

Created Result Type in TypeScript

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 });
Enter fullscreen mode Exit fullscreen mode

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.
}


Enter fullscreen mode Exit fullscreen mode

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")
}

Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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();

Enter fullscreen mode Exit fullscreen mode

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. 🦀🦀🦀

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay