Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions error-constructors.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
type BaseErrorConstructor = new (message?: string, ...arguments_: unknown[]) => Error;

/**
Let `serialize-error` know about your custom error constructors so that when `{name: 'MyCustomError', message: 'It broke'}` is found, it uses the right error constructor. If "MyCustomError" isn't found in the global list of known constructors, it defaults to the base `Error` error constructor.

Warning: The constructor must work without any arguments or this function will throw.
*/

type BaseErrorConstructor = new (message?: string, ...arguments_: unknown[]) => Error;
declare function addKnownErrorConstructor(constructor: BaseErrorConstructor): void;

export {addKnownErrorConstructor};
export function addKnownErrorConstructor(constructor: BaseErrorConstructor): void;
16 changes: 8 additions & 8 deletions error-constructors.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ const list = [
export const errorConstructors = new Map(list);

export function addKnownErrorConstructor(constructor) {
const {name} = constructor;
if (errorConstructors.has(name)) {
throw new Error(`The error constructor "${name}" is already known.`);
}

let instance;
try {
// eslint-disable-next-line no-new -- It just needs to be verified
new constructor();
instance = new constructor();
} catch (error) {
throw new Error(`The error constructor "${name}" is not compatible`, {cause: error});
throw new Error(`The error constructor "${constructor.name}" is not compatible`, {cause: error});
}

const {name} = instance;
if (errorConstructors.has(name)) {
throw new Error(`The error constructor "${name}" is already known.`);
}

errorConstructors.set(name, constructor);
Expand Down
26 changes: 26 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,32 @@ test('should not allow adding incompatible or redundant error constructors', t =
}, {message: 'The error constructor "BadError" is not compatible'});
});

test('should handle minified constructors correctly using instance name', t => {
class CustomError extends Error {
constructor(message) {
super(message);
this.name = 'CustomError';
}
}

// Simulate minification by changing constructor name
Object.defineProperty(CustomError, 'name', {
value: 'a', // Minified name
configurable: true,
});

addKnownErrorConstructor(CustomError);

const error = new CustomError('test message');
const serialized = serializeError(error);
t.is(serialized.name, 'CustomError');

const deserialized = deserializeError(serialized);
t.true(deserialized instanceof CustomError);
t.is(deserialized.name, 'CustomError');
t.is(deserialized.message, 'test message');
});

test('should deserialize plain object', t => {
const object = {
message: 'error message',
Expand Down