2

I want to wrap my service methods in a cachify method that checks the cache before querying the database. However, I am unable to preserve the type declaration of the wrapped function.

The wrapping cachify function looks like this:

// cache.ts
const cachify = async <T>(fn, args): Promise<T> => {
  const key = constructHashKey(args)
  const cachedEntry = get(key)

  if (cachedEntry) {
    return cachedEntry
  } else {
    const entry = await fn(...args)
    put(key, entry)
    return entry
  }
}

Here is an example of the usage of the wrapping function:

// userService.ts
const getUserProfilePhotoUrl = async (id: string, size: string): Promise<string> => {
  return cachify<string>(fetchPhotoUrl, [
    id,
    size
  ])
}

The fetchPhotoUrl function has the signature (id: string, size: string): Promise<string>.

However, if I add some arbitrary argument to the array [id, size], I do not get any type errors. How do I make Typescript aware of this?

1 Answer 1

1

You can get the desired behavior you just need to add some type parameters to the function to capture the actual parameter types being passed in.

const cachify = async <T, A extends [any] | any[]>(fn: (...a: A) => Promise<T>, args: A): Promise<T> => {
    const key = constructHashKey(args)
    const cachedEntry = get(key)

    if (cachedEntry) {
        return cachedEntry
    } else {
        const entry = await fn(...args)
        put(key, entry)
        return entry
    }

}

declare function fetchPhotoUrl(id: string, size: string): Promise<string>;
const getUserProfilePhotoUrl = async (id: string, size: string): Promise<string> => {
    return cachify(fetchPhotoUrl, [
        id,
        size
    ])
}

If all you will be doing is just forwarding parameter along the this version might make things easier:

const cachify = <T, A extends [any] | any[]>(fn: (...a: A) => Promise<T>): ((...args: A) => Promise<T>) => {
    return async function (...args: A) {
        const key = constructHashKey(args)
        const cachedEntry = get(key)

        if (cachedEntry) {
            return cachedEntry
        } else {
            const entry = await fn(...args)
            put(key, entry)
            return entry
        }
    }
}

declare function fetchPhotoUrl(id: string, size: string): Promise<string>;
const getUserProfilePhotoUrl = cachify(fetchPhotoUrl)

getUserProfilePhotoUrl("id", "");

getUserProfilePhotoUrl is fully type safe, you get a tooltip for the parameter names if you hover over the function but not when in actual code completion (this should get fixed in the future).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.