Skip to content

Instantly share code, notes, and snippets.

@wilmoore
Last active May 21, 2024 06:56
Show Gist options
  • Select an option

  • Save wilmoore/97558e68a01b3d5d05e20ef4686a2424 to your computer and use it in GitHub Desktop.

Select an option

Save wilmoore/97558e68a01b3d5d05e20ef4686a2424 to your computer and use it in GitHub Desktop.
Software Engineering :: Programming :: Languages :: JavaScript :: TypeScript :: Maybe<T>

Software Engineering :: Programming :: Languages :: JavaScript :: TypeScript :: Maybe<T>

⪼ Made with 💜 by Polyglot.

The Maybe Type in {Java,Type}Script

The Maybe<T> type is hands-down my favorite type because of it's improvement on readability.

In my opinion, Maybe<Error> is a much nicer way to say Error | null | undefined.

export type Maybe<T> = NonNullable<T> | null | undefined;

Now we can write, Maybe<string>, Maybe<boolean>, or something more involved like { data?: T; error?: Maybe<Error> }.

Async in JavaScript

A Promise in JavaScript is an object that encapsulates asyncronicity. A database connection, an HTTP request, or some other type of connection, in JavaScript is an asyncronous operation. In JavaScript, there are two APIs for working with asyncronicity:

  1. const fn = async () => {}
  2. const fn = () => new Promise()

Typing Async Functions in TypeScript

In JavaScript, when an asyncronous function returns a value, the value returned is wrapped in a Promise object. This means, either can use the fn().then().catch().finally() interface or the await fn() interface. They are completely interchangeable.

A promise is typed such that the return type is supplied to the Promise generic type as a type parameter. A string return value would be typed as Promise<string> and a promise returning a boolean value would be typed as Promise<boolean>.

Asyncronous Functions & Inconsistent Error Handling

Handling errors for new Promise is typically something like:

function go() {
  return new Promise((_, reject) => reject(new Error("no chance of success!!!")))
    .catch((error) => { console.error(error.message) })
}

Handling errors for async () => {} is:

async function go() {
  try {
    throw new Error("no chance of success!!!");
  } catch (error) {
    console.error(error.message);
  }
}

The MaybeAsyncData<T> type indicates that a function returning a new Promise() or async () => {} can be called without a try/catch wrapper.

type MaybeAsyncData<T> = { data?: T; error?: Maybe<Error> };

const fetchApiData = async (): MaybeAsyncData<string> => {
  return { data: "any string you like" };
};

The type MaybeAsyncData on it's own does nothing to mitigate the function rejecting or throwing an error; however, the following utility function helps:

function maybeAsyncData(fn: any, args: any): MaybeAsyncData<any> {
  return fn.apply(null, args).then((data) => ({ data })).catch((error) => ({ error }));
}

Error Handling with Async Functions

Regardless of the actual data a promise returns

Refactor This

try {
  const data = await somethingAsync();
  return data;
} catch (error) {
  console.log(`error: ${error.message}`);
}

To This

const { data, error } = await somethingAsync();
if (error)
  return false;
console.dir(data);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment