Msw: Typescript fails to compile the example code in the home page

Created on 21 Dec 2020  路  7Comments  路  Source: mswjs/msw

Describe the bug

I'm replicating the ts code in the home page:

import { setupWorker, rest } from 'msw'
interface LoginBody {
  username: string
}
interface LoginResponse {
  username: string
  firstName: string
}
const worker = setupWorker(
  rest.post<LoginBody, LoginResponse>('/login', (req, res, ctx) => {
    const { username } = req.body
    return res(
      ctx.json({
        username,
        firstName: 'John'
      })
    )
  }),
)
worker.start()

But it won't compile saying

TypeScript error in /project/src/integration-tests/mocks/handlers.ts(24,7):
Argument of type 'ResponseTransformer<string>' is not assignable to parameter of type 'ResponseTransformer<LoginResponse>'.
  Types of parameters 'res' and 'res' are incompatible.
    Type 'MockedResponse<LoginResponse>' is not assignable to type 'MockedResponse<string>'.
      Type 'LoginResponse' is not assignable to type 'string'.  TS2345

    22 |     const { username } = req.body
    23 |     return res(
  > 24 |       ctx.json({
       |       ^
    25 |         username,
    26 |         firstName: 'John'
    27 |       })

Environment

  • msw: ^0.24.2
  • nodejs: v12.18.0
  • npm: 6.14.4
  • typescript: Version 4.1.3

  • > Please also provide your browser version.
    Latest edge
DX bug typescript

Most helpful comment

Thanks for looking into it, @timdeschryver. Do I understand it correctly that type inference is lost because ctx.json returns a string? 馃 The intention is to infer the type given to rest.post generic.

Yes right, because now the json function will return a string instead of an object of type BodyType.

All 7 comments

Seems like this is a regression of #468.
I'm not sure which way we want/should go with this... using ctx.json returns a string (which is correct), but you lose some type safety with it. I wanted to suggest having a typed ctx.json, but it seems @kettanaito already thought of this 馃檪

If my thinking is correct, the example code should look like this:

import { setupWorker, rest } from 'msw'

interface LoginBody {
  username: string
}
interface LoginResponse {
  username: string
  firstName: string
}

const worker = setupWorker(
  rest.post<LoginBody>('/login', (req, res, ctx) => {
    const { username } = req.body
    return res(
      ctx.json<LoginResponse>({
        username,
        firstName: 'John',
      }),
    )
  }),
)
worker.start()

If that's the case, do you want to file a Pull Request for the docs @haikyuu ?

Thanks for looking into it, @timdeschryver. Do I understand it correctly that type inference is lost because ctx.json returns a string? 馃 The intention is to infer the type given to rest.post generic.

@timdeschryver thanks for your suggestion. It does work this way but it's no different than adding a @ts-ignore IMHO. What if I have multiple conditionals? Should I add the typing to each ctx.json call? It will be error prone and repetitive.

Using generics would probably allow ctx.json to pick the type from .post. So I believe this is a bug rather than something we need to update the docs for.

I downgraded to 0.23.0 for now. It's working as expected

Thanks for looking into it, @timdeschryver. Do I understand it correctly that type inference is lost because ctx.json returns a string? 馃 The intention is to infer the type given to rest.post generic.

Yes right, because now the json function will return a string instead of an object of type BodyType.

As @marcosvega91 confirmed, it's because the json function returns a string.

I'm not very familiar with the codebase, but I suppose this can be fixed by changing the argument type of json function to ctx.json(ResponseBodyType) by taking ResponseBodyType from the types given to the generics of get, post ...

Was this page helpful?
0 / 5 - 0 ratings