Service caching feature return types (TS)


I recently upgraded our Redwood app to version 3.8.0 in order to use the service caching feature with Redis. While working with the cache and cacheFindMany functions, I noticed that they are both typed to return Promise<any>, but the function input itself already has a generic type parameter <TResult>.

I’m wondering if there is a specific reason for returning Promise<any> instead of Promise<TResult>. In my opinion, using Promise<TResult> would provide more type safety and catch type errors at compile time. On the other hand, Promise<any> allows the resolved value to be of any type, which can be less predictable.

Are there other considerations to take into account when deciding on the return type?

Thanks for your help!

Hi Daniel, nice name and welcome to the community :fireworks:!

The cache function will serialize and deserialize your data automatically (i.e. call JSON.stringify before saving it in cache, and JSON.parse after retrieving it from the cache). In most cases this results in the same object you passed in - but if you have certain objects in your cached object, such as Dates, it’ll be converted to a string. In order to prevent misleading people, I thought its better to leave it as an any, and let you type the returned object manually. It’s briefly described here

Very happy to hear suggestions if you can think of a better solution (or where in the docs it would make sense to add clarity on this)!

1 Like

Hey Danny! Thanks for responding to my post!

Thanks for the explanation, I understand the reasoning behind using any as the return type. I can also see how it could be misleading if certain objects like Dates are not handled properly.

The documentation could maybe be improved by adding a reference style of docs where the types of certain modules and functions exported by Redwood are described in more detail. I know this is not a short order, but I am just shooting ideas :smile:.

An alternative solution I suggest is using a library like superjson to handle serialization and deserialization of data, which can handle different types of data, such as Dates, in a more robust way, by automatically converting them to a string representation when serializing and back to their original form when deserializing. It could provide more control over the serialization process and can handle other types of objects such as RegExp and Map. However, this would add an additional dependency and complexity to the project. I would love to hear your thoughts on this idea and if we could further improve the cache function overall.

I believe Next.js has a similar issue when it comes to some of their modules such as getStaticProps. I was inspired by this post.

Hmm, superjson does look very interesting - but I’m not sure these are exactly the same problems, because service caching does handle the se/deserialisation process for you (I believe), @rob can confirm if its all these cases though - screenshot below from their repo!

Now I’ve not used superjson yet… but if you look at one of the examples in their readme:

// The output type is being passed in here 👇
const object = superjson.parse<{ date: Date }>(jsonString);

Service caching also has something similar, but the syntax is different

Open to copy code```export const post = ({ id }) => { // 1. ⚠️ The type here refers to the return type from the function your are caching const cachedOutput = cache<{ id: number; createdAt: string }>( `cachedKey-${id}`,
// TS will error here, saying this function doesnt return the above type
() =>{
    where: { id },


// 2. But you can define the output type like this!
const typedOutput: Promise<{ id: number; createdAt: string }> = cache(
() =>{
where: { id },

return cachedOutput

Either way with superjson or not, I think you have to manually define the output type.

So the questions here then:

  1. Does the above syntax seem reasonable to you? Or should we also pass the output type as the generic, instead of the input type.
  2. Any interest in adding this to the service caching docs on our behalf? Always best when someone using it actually explains it! We can connect over discord to go over it together if you like!
  3. Have i misunderstood your suggestions completely and answered a completely different question? :stuck_out_tongue: