#How to type this so specific return doesn't complain from generic method?

6 messages · Page 1 of 1 (latest)

lament dune
#
class Foo {
    /** @type string */
    a = '';
}
class Bar {
    /** @type string */
    a = '';
    /** @type string */
    b = '';
}


const fooBar = {
    foo: new Foo(),
    bar: new Bar(),
}

/**
 * @param {'foo'|'bar'} fooOrBar
 * @returns {Foo|Bar}
 */
const getFooBar = (fooOrBar) => fooBar[fooOrBar];

/**
 * @returns {Foo}
 */
const getFoo = () => getFooBar('foo');

/**
 * @returns {Bar}
 */
const getBar = () => getFooBar('bar');

getBar is complaining because Type 'Foo | Bar' is not assignable to type 'Bar'. Property 'b' is missing in type 'Foo' but required in type 'Bar'. . That error makes perfect sense, but how can I set up the jsdoc comments so that there are no complaints since this is technically fine?

(obviously this is a simpler example to showcase the problem, but I have more complex logic that is essentially the same that I'd like to be able to have with "no complaints" without instead having to duplicate basically all of getFooBar within each getFoo and getBar)

hallow willow
#

modify your getFooBar comment to

/**
 * @template {'foo'|'bar'} K
 * @param {K} fooOrBar
 * @returns {(typeof fooBar)[K]}
 */
#

if there are more members of fooBar then you can replace the constraint in the @template tag to keyof typeof fooBar

lament dune
# hallow willow modify your `getFooBar` comment to ```js /** * @template {'foo'|'bar'} K * @pa...

Awesome, thanks. I looked into @template but wasn't sure how to make it work with my case.

It looks like I've also got a slightly more complex case, too. (I've got multiple cases and this one apparently doesn't quite fit the above outline)

Assuming foobar was

const foobar {
  foo: Foo[],
  bar: Bar[],
}

How would I type getFooBar if they instead looked like this?

/**
 * @param {'foo'|'bar'} fooOrBar
 * @returns {Foo|Bar}
 */
const getFooBar = (fooOrBar) => fooBar[fooOrBar][0];

/**
 * @returns {Foo}
 */
const getFoo = () => getFooBar('foo');

/**
 * @returns {Bar}
 */
const getBar = () => getFooBar('bar');

The difference being that foo and bar are both arrays but it's returning a single element. I can't seem to figure out how to manipulate your example for this case

hallow willow
#

same type but change the return to @returns {(typeof fooBar)[K][number]}

lament dune
#

Awesome, thanks 👍