0

I have a function getFruit() that returns two possible types, Banana | Apple.

I have a jest unit test that includes a test for a property that exists on one of the types, but not the other. In this case, Banana has the property peel but Apple does not.

test(`gets a banana`, () => {
  const fruit = getFruit(id)
  expect(fruit?.peel).toBeDefined();
})

I am content that fruit?.peel may not be defined when it is first referenced, as I am testing for fruit?.peel being defined in the same line.

However TS marks the fruit?.peel line as having an error:

Property 'peel' does not exist on type 'Banana | Apple'.
  Property 'peel' does not exist on type 'Apple'

How can I test a property on an object that may be of two different types using Jest and TypeScript?

I know I can disable the TS compiler with a ts-ignore, but I am hoping for a fix rather than a workaround.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • From the TypeScript side, you do have a problem - how will consumers use `getFruit`? The simplest way to tell the compiler "I know this will be a banana" is `const fruit = getFruit(id) as Banana;`. But how and why do you know that? Is there other type information you could leverage? – jonrsharpe May 03 '22 at 13:29

1 Answers1

1

While TypeScript won't let you access a property that isn't known to exist, it will let you check for its existence with the in operator:

expect('peel' in fruit).toEqual(true);

Or as jonrsharpe points out, it may be better to do this:

expect(fruit).toHaveProperty('peel');

which in the failing case outputs:

    expect(received).toHaveProperty(path)

    Expected path: "peel"
    Received path: []

    Received value: {"cultivar": "braeburn"}

rather than:

    expect(received).toEqual(expected) // deep equality

    Expected: true
    Received: false
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • The downside of `expect(something).toEqual(true)` is the [_diagnostics_](http://www.growing-object-oriented-software.com/figures/feedback-on-diagnostics.svg) tend to be poor when it fails. Unless you're actually testing some boolean, there's usually a better choice (in this case probably https://jestjs.io/docs/expect#tohavepropertykeypath-value). – jonrsharpe May 03 '22 at 13:16
  • 1
    @mikemaccana _"where I can test for the property being equal to a specific value"_ is also supported by the optional `value` parameter. This assertion is covered in e.g. https://stackoverflow.com/q/47754777/3001761, which you certainly seem to be aware of! – jonrsharpe May 03 '22 at 13:23
  • @jonrsharpe Ah yes, test the `result` matches an object, rather than checking if `result.property` has a particular value. I did ask that question but I don't often have functions return `A | B` so didn't consider it. – mikemaccana May 03 '22 at 13:33