Search code examples
typescriptoverloadingtypescript-typings

TypeScript overload: string or custom object as function argument and return type


I'm trying to overload a function in TypeScript.

Here is my code:

/**
 * Returns a 400 Bad Request error.
 *
 * @returns A response with the 400 status code and a message.
 */
export function badRequest(): TypedResponse<{ message: string }>;
/**
 * Returns a 400 Bad Request error.
 *
 * @param errors - An object containing the errors from the Zod schema.
 * @returns A response with the 400 status code, a message and the errors.
 */
export function badRequest<T>(
  errors: ZodFormattedError<T>,
): TypedResponse<{ message: string; errors: ZodFormattedError<T> }>;
/**
 * Returns a 400 Bad Request error.
 *
 * @param errors - An error string.
 * @returns A response with the 400 status code, a message and the errors.
 */
export function badRequest(
  errors: string,
): TypedResponse<{ message: string; errors: string }>;
export function badRequest<T>(errors?: ZodFormattedError<T> | string) {
  return json(
    { message: 'Bad Request', ...(errors && { errors }) },
    { status: 400 },
  );
}

const myRequest = badRequest({
  _errors: [
    {
      code: 'invalid_type',
      expected: 'string',
      received: 'number',
      path: ['name'],
      message: 'Expected string, received number',
    },
  ],
});

I want TypeScript to know, that when badRequest is called without any arguments, the return type only has a message, and when it is called with a string, it should have a property errors that contains a string and when it is called with a ZodFormattedError the errors property should be those errors.

I tried the code above, and TypeScript yells:

No overload matches this call.
  Overload 1 of 3, '(errors: ZodFormattedError<{ _errors: unknown; }, string>): TypedResponse<{ message: string; errors: ZodFormattedError<{ _errors: unknown; }, string>; }>', gave the following error.
    Type '{ code: string; expected: string; received: string; path: string[]; message: string; }' is not assignable to type 'string'.
  Overload 2 of 3, '(errors: string): TypedResponse<{ message: string; errors: string; }>', gave the following error.
    Argument of type '{ _errors: { code: string; expected: string; received: string; path: string[]; message: string; }[]; }' is not assignable to parameter of type 'string'.

How can I correctly overload this function?


Solution

  • Fixed it with these overloads:

    /**
     * Returns a 400 Bad Request error.
     *
     * @returns A response with the 400 status code and a message.
     */
    export function badRequest(): TypedResponse<{ message: string }>;
    /**
     * Returns a 400 Bad Request error.
     *
     * @param errors - An object containing the errors from the Zod schema.
     * @returns A response with the 400 status code, a message and the errors.
     */
    export function badRequest<T>(
      errors?: ZodFormattedError<T>,
    ): TypedResponse<{ message: string; errors: ZodFormattedError<T> }>;
    /**
     * Returns a 400 Bad Request error.
     *
     * @param errors - A string containing the errors.
     * @returns A response with the 400 status code, a message and the errors.
     */
    export function badRequest(
      errors?: string,
    ): TypedResponse<{ message: string; errors: string }>;
    export function badRequest<T>(
      errors?: ZodFormattedError<T> | string,
    ): TypedResponse<{ message: string; errors?: ZodFormattedError<T> | string }> {
      return json(
        { message: 'Bad Request', ...(errors && { errors }) },
        { status: 400 },
      );
    }