l2beat/earl

expect.subset() not type-safe

dhardtke opened this issue · 1 comments

Hi,

first of all: Thanks a lot for all the work you have put into earl. We are currently evaluating if we will switch from chai to it because the lack of type-safety is really an issue.

We have tons of chai assertions using chai-subset that are written like this:

const items = [
  { _id: 42, foo: 'bar' },
  { _id: 43, foo: 'baz' },
  { _id: 44, lorem: 'ipsum' }
];

expect(items).to.containSubset([
  { _id: 42 },
  { _id: 44 }
])

The same assertion can be written with earl using:

expect(items).toInclude(
  expect.subset({ _id: 42 }),
  expect.subset({ _id: 44 }),
)

However it is not type safe as the following would also compile:

expect(items).toInclude(
  expect.subset({ x: 'y' }),
)

I would expect subset() to only accept Partials or (or deep Partials) of the type of items that are passed to expect().

Okay so I had a go at fixing this and pretty quickly stumbled upon that expect.subset, like all the other matchers, returns as type never. This is an issue since never can be assigned to any type.

So in my opinion either we change the types of all matchers (or add an optional generic of type T to Matcher) so that we can capture what was given to the matcher and reuse that inside the validators.

Based on toInclude my fix would then look like this:

interface Validators<T> {
  toInclude(
        this: Validators<T>,
        ...items: MemberOf<T>[]
      ): void
}

Or maybe it's a better approach to add a new Validator altogether for validating whether objects are (partially) included in a given array. Not sure about introducing bloat to the API though.