Home > Net >  Typescript - Implementing Either with a tuple for error handling
Typescript - Implementing Either with a tuple for error handling

Time:06-12

Is it possible to compose a type which represents a tuple that returns either an error or the value?

async function createUser(userData): Promise<Either<User, UserError>> {}

// This should return a tuple where we have either an user or an error. Not both, not none
const [ user, userError ] = await createUser({ ... })

// Checking if there is an error
if (userError) {
    ...
    // This line represents an early bail, could be throw or return
    throw userError
}

// Since we check the error above, this should now be safe to use
console.log(user.name)

CodePudding user response:

You can create such a type like this:

type Either<A, B> = [A, undefined?] | [undefined, B];

And it will be handled by TypeScript's control flow analysis the way you want it to:

TS Playground

type Either<A, B> = [A, undefined?] | [undefined, B];

type User = { name: string };

class UserError extends Error {
  override name = 'UserError';
}

declare function createUser(userData: User): Promise<Either<User, UserError>>;

const [ user, userError ] = await createUser({name: 'foo'});

user; // User | undefined
userError; // UserError | undefined

if (userError) {
  userError; // UserError
  throw userError;
}

user; // User
user.name; // string


However, I prefer using a union to avoid the extra tuple and variable (inspired by Rust's Result type):

TS Playground

type Result <T = void, E extends Error = Error> = T | E;

function isError <T>(value: T): value is T & Error {
  return value instanceof Error;
}

type User = { name: string };

class UserError extends Error {
  override name = 'UserError';
}

declare function createUser(userData: User): Promise<Result<User, UserError>>;

const user = await createUser({name: 'foo'});

user; // User | UserError

if (isError(user)) {
  user; // UserError
  // ... do something else
  throw user;
}

user; // User
user.name; // string

  • Related