#generic type of variable based on parameter value (boolean)

19 messages · Page 1 of 1 (latest)

lusty helm
#

hello, let say I have function example, that returns either string or number based on boolean passed via parameter.

/**
 * @template {boolean} T
 * @param {T} bool
 * @returns {T extends true ? string : number}
 */
function example(bool) {
    return bool ? '1' : 1;
}

const x = example(true);
const y = example(false);

in this case, x has correct type string, and y has correct type number. But inside of function implementation it throws error:

Type 'string | number' is not assignable to type 'T extends true ? string : number'.
lost flower
#

yeah, it's not really possible to implement functions with conditional return types without type assertions. instead most people recommend using overload signatures

lusty helm
#

how can I do overload signatures in JSDoc?

lost flower
#

i'm not sure, sorry. i usually use real typescript syntax

lusty helm
#

thank you very much for help... will check it, and see what can be done

lost flower
#

i'm not sure if/how type assertions work with JSDoc, but another option is doing the equivalent of return bool ? '1' : 1 as T extends true ? string : number

lusty helm
#

omg, I solved it... with:

return /** @type {T extends true ? string : number} */ (bool ? '1' : 1);

it works correctly

lost flower
#

nice. i'm sure you're aware but that is not strictly checked, like i'm pretty sure you could flip the cases and won't get any errors, so you'll have to be careful in the implementation

#

also note that with this setup if bool is just boolean (not statically known to be specifically true or false), then i think you'll get number back, not like number | string

#

...actually maybe not in this specific example because of distributive conditional types (and because boolean is defined as true | false). nevermind

lusty helm
#

it works fine... it throws error if I swap cases

#

So this really works fine, exactly as I need.

#

this also throws, so it's really strict

#

the issue is if I provide default value:

#

but it's still much better than what I had... but if I omit it from parameters, and set it only in types, it works fine when parameter is provided, and when is not provided it gives merged type (e.g. string | number)

#

I solved that too. It's working perfectly