Return Promise or boolean depending on parameters with a default

Viewed 262

I've got some code which will either return a boolean or a Promise depending on the parameters.

function setGuid<B extends boolean>(guid: string, shouldValidate?: B): B extends true ? boolean : Promise<boolean>
function setGuid(guid: string, shouldValidate?: boolean): boolean | Promise<boolean> {
    if (shouldValidate){
        return true
    }
    return Promise.resolve(true);
}

This functionality works. If I call setGuid("*", false) it understands that the return type will be a Promise<boolean> likewise if I call setGuid("*", true) TypeScript understands the return type will be a boolean.

The issue is I cannot work out how to set a default return type, that being Promise<boolean> if shouldValidate (an optional param) is not provided - I want TypeScript to understand that setGuid("*") will return Promise<boolean>. Currently if I don't explictly provide false as the second parameter it thinks boolean | Promise<boolean> is being returned.

The error I'm getting when calling setGuid("*") is Property 'then' does not exist on type 'boolean | Promise<boolean>'. Property 'then' does not exist on type 'false'.

Any help will be greatly appreciated, thanks!

1 Answers

If you don't pass anything in as shouldValidate, then there is nothing for the compiler to use to infer the type of B. As such, it will tend to default to its constraint, which is boolean. This has poor behavior since B extends true ? boolean : Promise<boolean> will become the union boolean | Promise<boolean>, as you've seen.

In this case, you could add a generic parameter default to the overload call signature, like this:

function setGuid<B extends boolean = false>(
  guid: string, 
  shouldValidate?: B
): B extends true ? boolean : Promise<boolean>;

The compiler will use this default if it cannot otherwise infer B:

setGuid("*").then(x => x ? 0 : 1); // no error now

Okay, hope that helps; good luck!

Playground link to code

Related