Edge Cases and Special Values

Learn how go-errors handles complex JavaScript values and edge cases

Complex Objects

Nested Objects

import { goSync } from 'go-errors';

// Handling deeply nested objects
let [result, err] = goSync(() => {
  throw { nested: { deep: { value: 42 } } };
});
// err will be an Error with message: '{"nested":{"deep":{"value":42}}}'

// Handling arrays
let [result, err] = goSync(() => {
  throw [1, 2, 3];
});
// err will be an Error with message: '[1,2,3]'

// Mixed complex objects
let [result, err] = goSync(() => {
  throw { arr: [1, { x: 2 }], obj: { y: [3, 4] } };
});
// err will be an Error with message: '{"arr":[1,{"x":2}],"obj":{"y":[3,4]}}'

Circular References

let circular: any = { foo: "bar" };
circular.self = circular;

let [result, err] = goSync(() => {
  throw circular;
});
// err will be an Error with message: "JSON.stringify cannot serialize cyclic structures."

Special JavaScript Values

Symbol Handling

let sym = Symbol('test');
let [result, err] = goSync(() => {
  throw sym;
});
// err will be an Error with message: 'Symbol(test)'

BigInt Support

let [result, err] = goSync(() => {
  throw BigInt(9007199254740991);
});
// err will be an Error with message: '9007199254740991'

Function Objects

function testFn() { return 42; }
let [result, err] = goSync(() => {
  throw testFn;
});
// err will be an Error containing function representation

Date Objects

let date = new Date('2024-01-01');
let [result, err] = goSync(() => {
  throw date;
});
// err will be an Error with stringified date

RegExp Objects

let regex = /test/gi;
let [result, err] = goSync(() => {
  throw regex;
});
// err will be an Error with message: '/test/gi'

Error Stack Preservation

let [result, err] = goSync(() => {
  throw new Error('test');
});
// err.stack will contain the full stack trace
// err.stack will include 'test' and file information

Custom Error Properties

class CustomError extends Error {
  constructor(public code: number, message: string) {
    super(message);
    this.name = 'CustomError';
  }
}

let [result, err] = goSync(() => {
  throw new CustomError(500, 'test');
});
// err will be instanceof CustomError
// err.code will be 500
// err.name will be 'CustomError'

Nested Errors

let [result, err] = goSync(() => {
  const e = new Error('outer');
  e.cause = new Error('inner');
  throw e;
});
// err.message will be 'outer'
// err.cause.message will be 'inner'

Special Return Values

Undefined and Null

// Handling undefined
let [result, err] = await goFetch<undefined>('/api/empty');
// result will be undefined
// err will be null

// Handling null
let [result, err] = await goFetch<null>('/api/null');
// result will be null
// err will be null

Empty String and Zero Values

// Empty string
let [result, err] = goSync(() => "");
// result will be ""
// err will be null

// Zero
let [result, err] = goSync(() => 0);
// result will be 0
// err will be null

// False
let [result, err] = goSync(() => false);
// result will be false
// err will be null

HTTP Edge Cases

// Empty response
let [data, err] = await goFetch('/api/empty');
// data will be undefined or null depending on response

// Non-JSON response
let [text, err] = await goFetch<string>('/api/text', {
  responseTransformer: async (response) => {
    if (response instanceof Response) {
      return response.text();
    }
    return String(response);
  }
});

// Binary response
let [blob, err] = await goFetch<Blob>('/api/binary', {
  responseTransformer: async (response) => {
    if (response instanceof Response) {
      return response.blob();
    }
    throw new Error('Expected binary response');
  }
});

Best Practices

  1. Handle Circular References

    // ✅ Good: Check for circular structures
    function safeStringify(obj: unknown): string {
      try {
        return JSON.stringify(obj);
      } catch (e) {
        if (e instanceof Error && e.message.includes('circular')) {
          return 'Circular structure detected';
        }
        throw e;
      }
    }
    
  2. Preserve Error Properties

    // ✅ Good: Preserve custom properties
    class AppError extends Error {
      constructor(message: string, public details: Record<string, unknown>) {
        super(message);
        Object.setPrototypeOf(this, AppError.prototype);
      }
    }
    
  3. Type Safety with Special Values

    // ✅ Good: Type-safe handling
    function processValue<T>(value: T | undefined | null) {
      let [result, err] = goSync(() => {
        if (value === undefined) return 'undefined';
        if (value === null) return 'null';
        return String(value);
      });
      return [result, err] as const;
    }
    

See Also