Typed Error

type Examples = 1 | 2 | 3;
type ErrorTypes = 'err1' | 'err2' | 'err3';

// or just use Result<number>
const fn = (i: number): Result<number, Exception<ErrorTypes>> =>
  i < 0 ? new Ok(i) : new Err(Exception.of('err1'));

//Result<T>.unwrap()
//      .unwrapOr(T)
//      .unwrapOrElse((e: Error) => T)
//      .match((T) => T, (e: Error) => T)

const failableFn = (i: Examples) =>
  i < 0 ? i : Exception.of<ErrorTypes>(`err${i}`);

async function main() {
  const e1 = Exception.of<ErrorTypes>('err1', 'error message 1');
  const m1 = e1.toMap(); // {type: 'err1', message: 'error message 1'}, Exception -> Record<'type'|'message'| {options: {cause: unknown}}, any>
  const e2 = Exception.from(new Error('plain error')); // Error -> Exception<'Err_Error'>

  //tryingSync(() => T) || tryingSync([() => T, () => U, ..])
  const [r1, _, __] = tryingSync(
    [1, 2, 3].map((e: number) => () => failableFn(e as Examples)),
  );
  //panic
  r1.unwrap();

  //recoverable
  r1.unwrapOr(1);
  r1.unwrapOrElse((e) => {
    if (Exception.is<ErrorTypes>(e)) {
      switch (e.type) {
        case 'err1':
          return 1;
        case 'err2':
          return 2;
        case 'err3':
          return 3;
      }
    }
    return 3;
  });
  r1.match(
    (allow) => allow,
    (e) => {
      if (Exception.is<ErrorTypes>(e)) {
        switch (e.type) {
          case 'err1':
            return 1;
          case 'err2':
            return 2;
          case 'err3':
            return 3;
        }
      }
      return 3;
    },
  );

  //tryingAsync(() => Promise<T>) || tryingAsync([() => Promise<T>, () => Promise<U>, ..])
  const [p1, ___, ____] = await tryingAsync(
    //like Promise.all([])
    [1, 2, 3].map((e) => () => Promise.resolve(e)),
  );

  //new Range(start, end, step)
  Iterator.from(new Range(0, 10, 2)).toArray(); //[0,2,4,6]

  //new Fill(start, end, value)
  Iterator.from(new Fill(0, 10, 0));
}