Socket
Book a DemoInstallSign in
Socket

@typ3/throwable

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@typ3/throwable

🦾 A type-safe way to express error

latest
Source
npmnpm
Version
0.0.5
Version published
Maintainers
1
Created
Source

Throwable

A type-safe way to handle Error in TypeScript

codecov

Why

By default, we use try, catch, throw to handle error in JS/TS. But it's not type-safe -- we cannot tell what error a function may throw. It makes throw risky -- any unhandled error will make the program crash, which probably is not something we want.

All we need is a way to semantically tell us there might be a error that should be handled.

  • T | undefined lacks of detail info
  • T | Error is not convenient to work with

Haskell's Either type might be a solution to this scenario. This project rename it to Throwable for better readability.

We can use Throwable<TReturn, TError> to mark a return type of a function to declare it will return TError if error occurred, otherwise TReturn;

function div(a: number, b: number): Throwable<number, 'divZero' | 'divNaN'> {
  if (b === 0) {
    return Err('divZero');
  }

  if (Number.isNaN(b)) {
    return Err('divNaN');
  }

  return Ok(a / b);
}

function aDivBDivB(a: number, b: number): Throwable<number, 'divZero'> {
  return div(a, b).ifOk(c => div(c, b));
}


Usage

Install

yarn add @typ3/throwable

Basic usage

import {Ok, Err, Throwable} from '@typ3/throwable'
// in deno
import {Ok, Err, Throwable} from 'https://deno.land/x/throwable@v0'

function parse(input: string): Throwable<string[], 'invalid'> {
  const ans = []
  if (!input.startsWith('{')) {
    // Rather than `throw new Error()`
    return Err('invalid');
  }

  ...

  return Ok(ans);
}

Throwable interface

interface Throwable<TReturn, TError> {
  /**
   * return the concrete error if it is an error
   */
  get error(): TError | undefined
  /**
   * return the value if it is not an error
   */
  get value(): TReturn | undefined
  get isOk(): boolean;
  get isError(): boolean;
  /**
   * if `this.value` is not error, then return `func(this.value)`
   * otherwise return `this.error`
   */
  pipe<T>(func: (value: TReturn) => T): Throwable<T, TError>;
  /**
   * if this.value is valid, return this.value, otherwise return sub
   */
  or<T>(sub: T): TReturn | T;
  /**
   * if this.value is valid return it, otherwise throw the error
   */
  unwrap(): TReturn;
}

function Ok<TReturn, TError=any>(v: TReturn): Throwable<TReturn, TError>;
function Err<TError, TReturn=any>(v: TError): Throwable<TReturn, TError>;

Use Case

type MThrowable = Throwable<T, 'notExists' | {type: 'parseError', msg: string} >;

function readJsonFile<T>(path: string): Promise<MThrowable>{
  ...
}

async function readName(path: string): Promise<MThrowable>{
  return (await readJsonFile(path)).pipe(x => x.name);
}

function getValidNames(paths: string[]): Promise<string[]> {
  return Promise.all(paths.map(readName)).filter(x => x.isOk());
}

Keywords

js

FAQs

Package last updated on 17 Jan 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts