Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add type test for HttpResponse.error #2132

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

jacquesg
Copy link

No description provided.

@jacquesg
Copy link
Author

As expected, the CI is failing now due to the type error :)

@kettanaito
Copy link
Member

kettanaito commented May 8, 2024

Thanks for writing the tests, @jacquesg!

I think this hints at a more fundamental issue with how we annotate responses in MSW. See, this is the underlying type that everything depends on:

export type ResponseResolverReturnType<
ResponseBodyType extends DefaultBodyType = undefined,
> =
| ([ResponseBodyType] extends [undefined]
? Response
: StrictResponse<ResponseBodyType>)
| undefined
| void

And it expects a ResponseBodyType which is of type DefaultBodyType. For ResponseResolverReturnType to produce a non-strict, regular Response, the response body type argument must be undefined, which is valid per the DefaultBodyType type.

The issue happens when the response body type is supposed to be a union of types, like in case of GraphQL responses:

  • Either a strictly typed GraphQL JSON response;
  • Or a generic Response returned by Response.error().

I don't believe that type likes the union as the argument. We also don't teach it how to handle unions by doing something like X extends [undefined] or other dark TypeScript magic.


Here's an isolated playground.

@kettanaito
Copy link
Member

We can implement a fix like so and it will work.

It creates a different problem violating this expectation:

it('graphql query does not allow incompatible response body type', () => {
graphql.query<{ id: string }>(
'GetUser',
// @ts-expect-error incompatible response body type
() => HttpResponse.text('hello'),
)
})

Because the union produced to support Response.error() (return type of which is Response) now lets the HttpResponse.text() return type to pass even though its [bodyType] type is incompatible (it matches the generic Response type and since it's allowed, makes TS happy).

Preventing wrong mocked responses on the type level is a great feature to have. Unfortunately, Response.error() returns a generic Response type that cannot be discriminated against. This makes it impossible to tell apart a generic response type and an non-matching HttpResponse.* type because they come down to a generic Response anyway.

@kettanaito kettanaito added help wanted Extra attention is needed scope:typescript labels May 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed scope:typescript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants