Home > database >  How to type function params and make return type inferrable
How to type function params and make return type inferrable

Time:01-06

I want to create a standard type for a function that'll always receive the same type of params, but the ReturnType of the function will depend on the function's inferrable body.

So far I have these two ways to get the job done partially:

I can type the function's params, but the response doesn't get inferred anymore.

type Handler = (req: NextApiRequest, res: NextApiResponse) => unknown
const getExamples: Handler = async (req, res) => {
  // req gets typed as 'NextApiRequest'
  return db.example.findMany()
}
// ReturnType gets typed as unknown
export type GetExamplesResponse = ReturnType<typeof getExamples>

enter image description here

I can also infer the function's ReturnType, but the params are now implicitly any.

const getExamples = async (req, res) => {
  // req is implicitly "any"
  return db.example.findMany()
}

// ReturnType gets typed as Promise<Example[]>
export type GetExamplesResponse = ReturnType<typeof getExamples>

enter image description here

Is there a way to combine the best of both approaches into a single generic type/interface that'll let my IDE know the types of req & res and at the same time allow the ReturnType to be inferrable?

Here's a typescript playground example without the imported types

CodePudding user response:

If you specify the function type explicitly const getExamples: Handler - it will override the inferred type. Instead you could provide the type for the rest parameter:

type Params = [NextApiRequest, NextApiResponse]

const ex1 = async (...[req, res]: Params) => req.foo // Promise<string>
const ex2 = async (...[req, res]: Params) => res.bar // Promise<number>

Playground

Other option would be using "factory" function:

const createHandler = <T>(handler: (req: NextApiRequest, res: NextApiResponse) => T) => handler;

// (req: NextApiRequest, res: NextApiResponse) => Promise<string>
const ex1 = createHandler(async (req, res) => {
    return req.foo
})

// (req: NextApiRequest, res: NextApiResponse) => Promise<number>
const ex2 = createHandler(async (req, res) => {
    return res.bar
})

Playground

  •  Tags:  
  • Related