hoangvvo / next-connect

The TypeScript-ready, minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2
https://www.npmjs.com/package/next-connect
MIT License
1.63k stars 65 forks source link

Improve TypeScript interface to catch errors in `NextApiResponse` #111

Open Kerumen opened 3 years ago

Kerumen commented 3 years ago

When using next-connect with the generics, we don't have any error if we return a wrongly shaped response:

Screenshot 2020-11-14 at 16 37 24
const handler = nc<NextApiRequest, NextApiResponse>()

handler.get<NextApiRequest, NextApiResponse<{ success: boolean }>>(
  async (req, res) => {
    res.json({ success: '42' })
  }
)

However when we declare types directly in the params, we correctly have the error:

Screenshot 2020-11-14 at 16 37 29
const handler = nc<NextApiRequest, NextApiResponse>()

handler.get(
  async (req: NextApiRequest, res: NextApiResponse<{ success: boolean }>) => {
    res.json({ success: '42' })
  }
)

Can we try to improve the typings of the library to get the error? If we write this it works but I'm not sure that's the good way to fix it.

get<T = {}, S = {}>(...handlers: RequestHandler<U | T, V | S>[]): this;
hoangvvo commented 3 years ago

Hey @Kerumen, sorry for the late response!

get<T = {}, S = {}>(...handlers: RequestHandler<U | T, V | S>[]): this; will probably break the type since TS will not be able to tell if req and res is IncomingMessage and ServerResponse anymore.

This is a fix but I have not tested it out:

// HERE:
const handler = nc<NextApiRequest, NextApiResponse<unknown>>()

handler.get(
  async (req: NextApiRequest, res: NextApiResponse<{ success: boolean }>) => {
    res.json({ success: '42' })
  }
)

This forces the body inside res.json and res.send to only be unknown. Thus, this will break all the remaining res.json/res.send else unless you explicit type it like NextApiResponse<{ success: boolean }>

Let me know if it works for you so I can update the doc with this. Thanks!

Kerumen commented 3 years ago

Thanks for your answer. This works however we must repeat 2 times NextApiResponse and I wanted to avoid that. But it seems it's the only way to do it.