From 94b61005aff95c2b6bc79d16bfd89ad5d7b57064 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:37:30 +0000 Subject: [PATCH 1/5] Initial plan From a0b5324c1a7c734ed5f6bb6657794983708c5b7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:42:32 +0000 Subject: [PATCH 2/5] Add superArgsFn parameter to createCustomError for flexible argument ordering Co-authored-by: nev21 <82737406+nev21@users.noreply.github.com> --- lib/src/helpers/customError.ts | 36 ++++++- lib/test/src/common/helpers/throw.test.ts | 117 ++++++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/lib/src/helpers/customError.ts b/lib/src/helpers/customError.ts index 745204e4..439c5933 100644 --- a/lib/src/helpers/customError.ts +++ b/lib/src/helpers/customError.ts @@ -55,6 +55,10 @@ function _setName(baseClass: any, name: string) { * @param constructCb - [Optional] An optional callback function to call when a * new Customer Error instance is being created. * @param errorBase - [Optional] (since v0.9.6) The error class to extend for this class, defaults to Error. + * @param superArgsFn - [Optional] An optional function that receives the constructor arguments and + * returns the arguments to pass to the base class constructor. When not provided all constructor + * arguments are forwarded to the base class. Use this to support a different argument order or + * to pass a subset of arguments to the base class (similar to calling `super(...)` in a class). * @returns A new Error `class` * @example * ```ts @@ -115,13 +119,41 @@ function _setName(baseClass: any, name: string) { * theStartupError instanceof Error; // true * theStartupError instanceof AppError; // true * theStartupError instanceof StartupError; // true + * + * // ---------------------------------------------------------- + * // Custom error with reordered / transformed arguments + * // (the superArgsFn maps constructor args to base class args) + * // ---------------------------------------------------------- + * + * interface HttpErrorConstructor extends CustomErrorConstructor { + * new(statusCode: number, message: string): HttpError; + * (statusCode: number, message: string): HttpError; + * } + * + * interface HttpError extends Error { + * readonly statusCode: number; + * } + * + * // HttpError takes (statusCode, message) but base Error expects (message) + * let MyHttpError = createCustomError("HttpError", + * (self, args) => { + * self.statusCode = args[0]; + * }, + * Error, + * (args) => [ args[1] ] // pass only the message to base Error constructor + * ); + * + * let err = new MyHttpError(404, "Not Found"); + * err.message; // "Not Found" + * err.statusCode; // 404 * ``` */ /*#__NO_SIDE_EFFECTS__*/ export function createCustomError( name: string, constructCb?: ((self: any, args: IArguments) => void) | null, - errorBase?: B): T { + errorBase?: B, + superArgsFn?: ((args: IArguments) => any[]) | null): T { let theBaseClass = errorBase || Error; let orgName = theBaseClass[PROTOTYPE][NAME]; @@ -131,7 +163,7 @@ export function createCustomError { assert.ok(theError instanceof ApplicationError, "Check that the startupError is an ApplicationError"); }); }); + + describe("createCustomError with superArgsFn", () => { + it("reorders arguments before passing to base class", () => { + interface HttpErrorConstructor extends CustomErrorConstructor { + new(statusCode: number, message: string): HttpError; + (statusCode: number, message: string): HttpError; + } + + interface HttpError extends Error { + readonly statusCode: number; + } + + let MyHttpError = createCustomError("HttpError", + (self, args) => { + self.statusCode = args[0]; + }, + Error, + (args) => [ args[1] ] // pass only the message to base Error constructor + ); + + let err = _expectThrow(() => { + throw new MyHttpError(404, "Not Found"); + }, "Not Found"); + + assert.ok(err instanceof Error, "The custom error is an Error"); + assert.ok(isError(err), "isError returns true"); + assert.equal(err.name, "HttpError", "Name is HttpError"); + assert.equal(err.message, "Not Found", "Message is set from second arg"); + assert.equal(err.statusCode, 404, "statusCode is set from first arg"); + }); + + it("passes subset of arguments to base class", () => { + interface DetailedErrorConstructor extends CustomErrorConstructor { + new(message: string, code: number, detail: string): DetailedError; + (message: string, code: number, detail: string): DetailedError; + } + + interface DetailedError extends Error { + readonly code: number; + readonly detail: string; + } + + let MyDetailedError = createCustomError("DetailedError", + (self, args) => { + self.code = args[1]; + self.detail = args[2]; + }, + Error, + (args) => [ args[0] ] // pass only message to base Error + ); + + let err = _expectThrow(() => { + throw new MyDetailedError("Something failed", 42, "extra detail"); + }, "Something failed"); + + assert.ok(err instanceof Error, "The custom error is an Error"); + assert.ok(isError(err), "isError returns true"); + assert.equal(err.name, "DetailedError", "Name is DetailedError"); + assert.equal(err.message, "Something failed", "Message is set correctly"); + assert.equal(err.code, 42, "code is set correctly"); + assert.equal(err.detail, "extra detail", "detail is set correctly"); + }); + + it("works with custom error base class", () => { + interface AppErrorConstructor extends CustomErrorConstructor { + new(message: string): AppError; + (message: string): AppError; + } + interface AppError extends Error {} + + interface ServiceErrorConstructor extends CustomErrorConstructor { + new(service: string, message: string): ServiceError; + (service: string, message: string): ServiceError; + } + interface ServiceError extends AppError { + readonly service: string; + } + + let AppErrorCls = createCustomError("AppError"); + let ServiceErrorCls = createCustomError("ServiceError", + (self, args) => { + self.service = args[0]; + }, + AppErrorCls, + (args) => [ args[1] ] // pass message to AppError base class + ); + + let err = _expectThrow(() => { + throw new ServiceErrorCls("auth-service", "Unauthorized"); + }, "Unauthorized"); + + assert.ok(err instanceof Error, "is an Error"); + assert.ok(err instanceof AppErrorCls, "is an AppError"); + assert.ok(err instanceof ServiceErrorCls, "is a ServiceError"); + assert.ok(isError(err), "isError returns true"); + assert.equal(err.name, "ServiceError", "Name is ServiceError"); + assert.equal(err.message, "Unauthorized", "Message is set from second arg"); + assert.equal(err.service, "auth-service", "service is set from first arg"); + }); + + it("null superArgsFn behaves like no superArgsFn (passes all args)", () => { + interface MyErrorConstructor extends CustomErrorConstructor { + new(message: string): MyError; + (message: string): MyError; + } + interface MyError extends Error {} + + let MyErrorCls = createCustomError("MyNullSuperError", null, Error, null); + + let err = _expectThrow(() => { + throw new MyErrorCls("hello"); + }, "hello"); + + assert.ok(isError(err), "isError returns true"); + assert.equal(err.message, "hello", "Message is set correctly"); + }); + }); }); From cafc2874fbc7dce1ef65072f166555bc6193ae04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Feb 2026 01:50:05 +0000 Subject: [PATCH 3/5] docs: Add since v0.12.7 to superArgsFn parameter documentation Co-authored-by: nev21 <82737406+nev21@users.noreply.github.com> --- lib/src/helpers/customError.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/helpers/customError.ts b/lib/src/helpers/customError.ts index 439c5933..7d51cc2e 100644 --- a/lib/src/helpers/customError.ts +++ b/lib/src/helpers/customError.ts @@ -55,7 +55,7 @@ function _setName(baseClass: any, name: string) { * @param constructCb - [Optional] An optional callback function to call when a * new Customer Error instance is being created. * @param errorBase - [Optional] (since v0.9.6) The error class to extend for this class, defaults to Error. - * @param superArgsFn - [Optional] An optional function that receives the constructor arguments and + * @param superArgsFn - [Optional] (since v0.12.7) An optional function that receives the constructor arguments and * returns the arguments to pass to the base class constructor. When not provided all constructor * arguments are forwarded to the base class. Use this to support a different argument order or * to pass a subset of arguments to the base class (similar to calling `super(...)` in a class). From 0db2b46d6bb3504d5add91ed54082df8a1d3bd63 Mon Sep 17 00:00:00 2001 From: nev21 <82737406+nev21@users.noreply.github.com> Date: Wed, 25 Feb 2026 18:13:56 -0800 Subject: [PATCH 4/5] Update lib/src/helpers/customError.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lib/src/helpers/customError.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/helpers/customError.ts b/lib/src/helpers/customError.ts index 7d51cc2e..3cf5bbdd 100644 --- a/lib/src/helpers/customError.ts +++ b/lib/src/helpers/customError.ts @@ -53,7 +53,7 @@ function _setName(baseClass: any, name: string) { * @group Error * @param name - The name of the Custom Error * @param constructCb - [Optional] An optional callback function to call when a - * new Customer Error instance is being created. + * new Custom Error instance is being created. * @param errorBase - [Optional] (since v0.9.6) The error class to extend for this class, defaults to Error. * @param superArgsFn - [Optional] (since v0.12.7) An optional function that receives the constructor arguments and * returns the arguments to pass to the base class constructor. When not provided all constructor From 2aae5c98dda051ed54f18e85b8283bd4164f9abb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Feb 2026 02:16:31 +0000 Subject: [PATCH 5/5] refactor: Widen superArgsFn return type from any[] to ArrayLike Co-authored-by: nev21 <82737406+nev21@users.noreply.github.com> --- lib/src/helpers/customError.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/helpers/customError.ts b/lib/src/helpers/customError.ts index 3cf5bbdd..9e710c29 100644 --- a/lib/src/helpers/customError.ts +++ b/lib/src/helpers/customError.ts @@ -153,7 +153,7 @@ export function createCustomError void) | null, errorBase?: B, - superArgsFn?: ((args: IArguments) => any[]) | null): T { + superArgsFn?: ((args: IArguments) => ArrayLike) | null): T { let theBaseClass = errorBase || Error; let orgName = theBaseClass[PROTOTYPE][NAME];