useFetch type inference

Hello! Been using nuxt for a few days now and most things are amazing so far, love the overall DX. I do have one small gripe with useFetch though. Take the following code
const { data: recipe } = await useFetch(`/api/recipes/${id}`);
const { data: recipe } = await useFetch(`/api/recipes/${id}`);
This seems to infer the types, at least somewhat, but it leads to strange linting errors not letting me access the values of the recipe. However if I do the following and use a generic it does work as i expect it to.
const { data: recipe } = await useFetch<Recipe>(`/api/recipes/${id}`);
const { data: recipe } = await useFetch<Recipe>(`/api/recipes/${id}`);
Do I really need to use generics everytime I fetch data to get the correct type inference? Don't get me wrong, it's not the biggest hassle, until I change what data the route returns for example. Then it could mean changing the generic in a lot of places.
4 Replies
kapa.ai
kapa.ai7d ago
Hi @ThoorAdam. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- You're right about the type inference behavior with useFetch in Nuxt. Let me explain what's happening and how to handle it. Type Inference with useFetch When you use useFetch without explicitly providing a generic type:
const { data: recipe } = await useFetch(`/api/recipes/${id}`);
const { data: recipe } = await useFetch(`/api/recipes/${id}`);
The issue you're experiencing is related to how Nuxt serializes data from API routes. By default, when fetching data from the server directory, the response is serialized using JSON.stringify, which has limitations with JavaScript types. Nuxt tries to convert the return type of useFetch to match the actual value, but this can lead to type inference issues. As you've discovered, providing an explicit generic type resolves these issues:
const { data: recipe } = await useFetch<Recipe>(`/api/recipes/${id}`);
const { data: recipe } = await useFetch<Recipe>(`/api/recipes/${id}`);
Why This Happens This behavior occurs because of how Nuxt handles serialization between the server and client. When data is returned from an API route, it's serialized with JSON.stringify, which can only handle JavaScript primitive types. The type system tries to account for this, but it's not always perfect Data Fetching - Serializing Data From API Routes. Solutions 1. Use generics as you've been doing - This is the most straightforward approach for ensuring type safety. 2. Define a toJSON method on your returned object - If you control the API endpoint, you can customize the serialization behavior:
// server/api/recipes/[id].ts
export default defineEventHandler(() => {
const data = {
// recipe data
toJSON() {
return this; // This helps Nuxt respect the return type
}
}
return data;
})
// server/api/recipes/[id].ts
export default defineEventHandler(() => {
const data = {
// recipe data
toJSON() {
return this; // This helps Nuxt respect the return type
}
}
return data;
})
3. Use an alternative serializer - For more complex cases, you can use a different serializer like superjson:
// server/api/recipes/[id].ts
import superjson from 'superjson'

export default defineEventHandler(() => {
const data = {
// recipe data
toJSON() {
return this
}
}
return superjson.stringify(data) as unknown as typeof data
})
// server/api/recipes/[id].ts
import superjson from 'superjson'

export default defineEventHandler(() => {
const data = {
// recipe data
toJSON() {
return this
}
}
return superjson.stringify(data) as unknown as typeof data
})
And then in your component:
import superjson from 'superjson'

const { data } = await useFetch(`/api/recipes/${id}`, {
transform: (value) => {
return superjson.parse(value as unknown as string)
},
})
import superjson from 'superjson'

const { data } = await useFetch(`/api/recipes/${id}`, {
transform: (value) => {
return superjson.parse(value as unknown as string)
},
})
Using an alternative serializer Recommendation While it might seem tedious to use generics everywhere, it's currently the most reliable approach for ensuring type safety with useFetch. If you're concerned about maintaining types across multiple fetch calls, consider creating a custom fetch composable that encapsulates your API types. The Nuxt team is aware of these type inference challenges, as evidenced by several GitHub PRs addressing type-related issues with useFetch (PR #28993, PR #30531). Let me know if you need more specific guidance for your use case! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7d ago
<@198832691402113024> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
ThoorAdam
ThoorAdamOP7d ago
I created a composable as suggested by kapa.ai, I think this will suffice and make things more maintainable for now.
const { data: recipe } = await useRecipeById(id);
const { data: recipe } = await useRecipeById(id);
Cake
Cake6d ago
but it leads to strange linting errors not letting me access the values of the recipe
can u share the errors?

Did you find this page helpful?