Skip to main content

Ahh

Ahh is a collection of idiomatic type-safety functions that are borrowed from other languages. While it can make your code more verbose in certain areas, it also helps to keep it working as intended.

Demystification

While it may look like it from that outside, Option and Result are nothing special, at least compared to how you would normally handle such cases. A quick look at the types for both of them shows how bland they really are:

type None = undefined | null;
type Some<T> = T;
type Option<T> = None | Some<T>;

// this is the most exciting it gets folks
type Err<E extends Error> = E;
type Ok<T> = T;
type Result<T, E extends Error> = Err<E> | Ok<T>;

When you compare that to how everything else handles optional values, there’s no difference. The biggest departure is with how Result works, and that’s due to TS having no concept of it to begin with; but even then it still sticks to using the built-in Error type.

So let’s take a look at some Options and Results in actual code:

import { Option, Result } from "./mod.ts";

// `prompt` returns a `string` or `null`
const input: Option<string> = prompt("URL:");

// `new URL` returns a `URL` or throws an `Error`
const url: Option<Result<URL, Error>> = input ? (() => {
  try {
    return new URL(input);
  } catch (e) {
    return e;
  }
})() : null;

As you can see, the most convoluted part is dealing with errors, which we need to explicitly catch. And that’s all Ahh does, fill in those gaps to make this much easier:

import { O, Option, R, Result } from "./mod.ts";

// no changes here; apart from removing the unnecessary typing
const input = prompt("URL:");

// so much easier
const url = input ? R.fn(() => new URL(input)) : null;

// we can even go a step further
const url2 = O.map(prompt("URL:"), (url) => R.fn(() => new URL(url)));

// the "actual" types of these are just the bare types; no class weirdness
input; // string
url; // URL
url2; // URL | null

Licence

All code in this project is dual-licenced under either:

at your option.

Contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 licence, shall be dual licenced as above, without any additional terms or conditions.