Hendrixer/fullstack-music

Another way to wrap HOC function with typescript check

Closed this issue · 1 comments

In the course, I got an error Parameter 'handler' implicitly has an 'any' type. if I don't give handler type with any.
Below is my solution, hope this can help. ;)

// lib/auth.ts
export const validateRoute = (
  handler: any // I have to give type any, and the error will disappear
) => {
  return async (
    req: NextApiRequest,
    res: NextApiResponse
  ): Promise<void> => {
    const { SPOTIFY_ACCESS_TOKEN: token } = req.cookies

    if (token) {
      let user

      try {
        const { id } = verify(token, 'hello') as JwtPayload
        user = await prisma.user.findUnique({
          where: { id },
        })

        if (!user) {
          throw new Error('Not real user')
        }
      } catch (e) {
        return res.status(401).json({ error: 'Not authorized' })
      }

      return handler(req, res, user)
    }

    return res.status(401).json({ error: 'Not authorized' })
  }
}

So I wrapped user to req method, tweak a little bit code, and this work very well. ;)

// lib/auth.ts
import { JwtPayload, verify } from 'jsonwebtoken'
import type { NextApiRequest, NextApiResponse } from 'next'
import prisma from './prisma'

export type NextApiRequestWithUser = NextApiRequest & { user: JwtPayload } // need to export this to me.ts

// higher order function wrapper for validateRoute
export const validateRoute = (
  handler: (req: NextApiRequestWithUser, res: NextApiResponse) => void
) => {
  return async (
    req: NextApiRequestWithUser,
    res: NextApiResponse
  ): Promise<void> => {
    const { SPOTIFY_ACCESS_TOKEN: token } = req.cookies

    if (token) {
      let user

      try {
        const { id } = verify(token, 'hello') as JwtPayload
        user = await prisma.user.findUnique({
          where: { id },
        })

        if (!user) {
          throw new Error('Not real user')
        }
      } catch (e) {
        return res.status(401).json({ error: 'Not authorized' })
      }

      req.user = user // register user to req

      return handler(req, res)
    }

    return res.status(401).json({ error: 'Not authorized' })
  }
}
// pages/api/me.ts
import { NextApiResponse } from 'next'
import { NextApiRequestWithUser, validateRoute } from '../../lib/auth'

export default validateRoute(
  (req: NextApiRequestWithUser, res: NextApiResponse) => {
    res.json(req.user)
  }
)

eslint will show an 'no-unused-vars' error. Below is my solution.
ref: https://stackoverflow.com/questions/55807329/why-eslint-throws-no-unused-vars-for-typescript-interface

// eslint.js
rules: {
'@typescript-eslint/no-unused-vars': [
      2,
      {
        args: 'none',
      },
    ],
}

I did it like this export const validateRoute = (handler: Function) => {...}