heast v0.1.0
heast
Small, type-safe, function wrapper for better error handling and input/output-validation with zod. Inspired by neverthrow.
Usage
Install package:
# npm
npm install heast
# yarn
yarn install heast
# pnpm
pnpm install heast
Import:
// ESM
import {} from "heast";
// CommonJS
const {} = require("heast");
Introduction
heast aims to be the default way to define a function in your project. It is a wrapper around a function that returns a Result
object. The Result
object is a type-safe way to handle errors. It is inspired by neverthrow, but written from scratch.
It also includes input + output validation using zod.
Examples
Ok and Err
const getName = defineFunction({
output: z.string(),
handler: ({ ok }) => ok("Jakob"),
});
const name = getName(); // Result containing "Jakob"
const failToGetName = defineFunction({
output: z.string(),
handler: ({ err }) => err("NOT_FOUND", "Could not find name"),
});
const nameError = failToGetName(); // Result containing an error with name "NOT_FOUND" and message "Could not find name"
As you can see, the handler
function is called with an object containing the ok
and err
functions. These functions are used to return a Result
object. The ok
function returns a Result
object with the value Jakob
and the err
function returns a Result
object with the error Error
.
Error map
const withErrorMap = defineFunction({
input: z.number(),
errors: {
CANT_BE_ONE: "Number cannot be 1",
},
handler({ input, err, ok }) {
if (input === 1) {
return err("CANT_BE_ONE", "Number cannot be 1");
}
return ok();
},
});
const withErrorMapResult = withErrorMap(1); // Result containing an error with name "CANT_BE_ONE" and message "Number cannot be 1"
The errors
object is used to map error names to error messages. This is useful when you want to return a custom error message to the user. The error name is used to identify the error, while the error message is used to display the error to the user.
The error name is automatically inferred when calling err
.
Async functions
const asyncFunction = defineFunction({
input: z.number(),
output: z.string(),
async: true,
handler: async ({ input, ok }) => {
const result = await someAsyncFunction(input);
return ok(result);
},
});
Async functions work exactly the same as normal functions. The only difference is that the handler
function is marked as async and async is set to true.
Match Results
const uncertainOutcome = defineFunction({
output: z.string(),
errors: {
UNLUCKY: "You were unlucky",
},
handler: ({ ok, err }) => {
let rand = Math.random();
if (rand > 0.5) {
return ok(`You were lucky! ${rand}`);
}
return err("UNLUCKY", "You were unlucky");
},
});
const result = uncertainOutcome();
result.match({
err: {
UNLUCKY: (error) => {
console.log(error);
},
},
ok: (data) => {
console.log(data);
},
});
1 year ago