Instead of relying on throwing an
Error, it’s sometimes more expressive to handle control flow by returning a
Result. Here’s how to implement such a construct in TypeScript.
Let’s start with a simple type that can hold a value or
const something: Result<string> = 'something'; is valid, as is
const somethingElse: Result<string> = new Error();.
The next step is to differentiate the two at runtime. I can easily check if something is an
instanceof, which TypeScript understands as a form of inline type guard.
Caution: You can throw something that isn’t an
Error, and this can be an issue if not addressed carefully when creating custom error hierarchies, particularly with transpiled code.
// This works well enough:if someResult instanceof Error// This is a bit clunky, and it would be easy to omit the parentheses and introduce a bug:if !someResult instanceof Error
To streamline the type check, I’d like to encapsulate it in a function. (Negating the result of a function call is clearer than negating an
The problem we’ll see is that TypeScript doesn’t propagate any type checks performed in a function into its caller. It will still treat the checked
Result as potentially being an
Error. Here’s what happens:
To fix this issue, we can add an explicit type guard to the
ok() function, which is written as
r is T. This asserts that when the function returns
Result that it was called with is the type
In summary, all we need for a working
Result type is the following: