Next.js Discord

Discord Forum

Next 13 API fetch return types

Unanswered
Common Pochard posted this in #help-forum
Open in Discord
Common PochardOP
What is the appropriate way to cast my data to the correct return types of Next APIs?

Currently, I have:
import { GET } from '@/app/api/todos/route';

async function MyPage() {
  const data: Awaited<ReturnType<typeof GET>> = await fetch('http://localhost:3000/api/todos').then((r) => r.json());

  return <> </>
}


This is close, but data ends up as:
const data: NextResponse<{
    id: number;
    name: string;
}[]>


This isn't iterable. How would I unwrap the NextResponse part of it?

11 Replies

Common PochardOP
I'm familiar with TRPC.

I'm just asking from a foundational perspective, there should be a really simple TS solution, I'm guessing.

For instance, I could wrap the internals of GET in an exported function, call the function inside of GET and use that function for my type declaration, and it would work, just wondering if there's a way where I can do it with GET directly.

Similar to this project that worked with the pages directory:
https://github.com/alii/nextkit-demo/blob/db7106a99e796b19aebbc2746dea38a16eaaad96/src/pages/index.tsx#L7
Common PochardOP
Yeah, I gotcha, I'm not denying trpc would be better, I'm not building a prod app, not really a 'whats the best way to do this?' question, just more a curious TS one
For instance, I could wrap the internals of GET in an exported function, call the function inside of GET and use that function for my type declaration, and it would work, just wondering if there's a way where I can do it with GET directly.
yeah that would be ideal solution, you don't want to add an extra request to your own server if you can execute the logic directly in your RSC

as for the question itself, the easiest solution would be to export your own type from the route handler and use it to type the response, like this:
import { ResponseX } from '@/app/api/todos/route'

// This probably shouldn't be in this file
const get = async <T,>(url) => {
  const res = await fetch(url)
  const data = await res.json() as T
  return data
}

async function Page() {
  const data = await get<ResponseX>('...')
}
if you want to infer the response from the return of the route handler methods, like GET, then it is harder because the Response class doesn't contain the type information of the body of the response. so you would need to wrap these methods with your own function that contains the type info
Common PochardOP
Found a way:
type NextApiRes<T extends (...args: any[]) => Promise<NextResponse<unknown>>> = Awaited<
  ReturnType<T>
> extends NextResponse<infer U>
  ? U
  : never;

declare const data: NextApiRes<typeof GET>;