Search code examples
typescripterror-handlingcurrying

Type for a curryfied function that create a new instance


So, i have the next function in ts:

export function createErrorInstance(error: unknown): Error {
    return new Error(getErrorMessage(error));
}

But now i want to create a curried function, that will accept the constructor new Error or new ServiceError so later on will return an other function expecting only for the error.

export const errorBuilder  = (builder: new (arg0: string) => any) =>
    (error: unknown) => 
        new builder(getErrorMessage(error))

which could be used as:

export const createErrorService = errorBuilder(ServiceError)

and later on, simply like: createErrorService(error) if i am in a try/catch fetch or createValidationError(error) if i am in a try/catch form validation.

Now I want to set it up the correct types, cuz now the signature for my createErrorService function is:

const createErrorService: (error: unknown) => any

but i wanted it to be: const createErrorService: (error: unknown) => ServiceError

Maybe i need to update the signature for errorBuilder, but i dont know how :(


Solution

  • You need errorBuilder() to be generic in the subtype of Error that the builder parameter constructs. Like this:

    export const errorBuilder = <T extends Error>(builder: new (arg0: string) => T) =>
      (error: unknown) =>
        new builder(getErrorMessage(error));
    
    // const errorBuilder: <T extends Error>(
    //   builder: new (arg0: string) => T
    // ) => (error: unknown) => T
    

    The generic type parameter T represents the subtype of Error that you care about. Note that it is constrained to Error via the T extends Error declaration, so you can be sure that T must be assignable to Error. The type of errorBuilder as shown above is therefore a function that takes a constructor of type T and returns a function whose return type is T.

    Let's test it out:

    export const createErrorService = errorBuilder(ServiceError);
    // const createErrorService: (error: unknown) => ServiceError
    
    const err = createErrorService({ a: 123 });
    // const err: ServiceError
    

    Looks good. The type of createErrorService is (error: unknown) => ServiceError as desired, and therefore any error you create with it is a ServiceError.

    Playground link to code