Typescript中的Typesafe包装函数

时间:2019-02-24 10:41:38

标签: typescript types

我想将我的服务方法包装在一个cachify方法中,该方法在查询数据库之前检查缓存。但是,我无法保留包装函数的类型声明。

包装cachify函数如下所示:

// 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
  }
}

以下是包装函数用法的一个示例:

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

fetchPhotoUrl函数具有签名(id: string, size: string): Promise<string>

但是,如果我向数组[id, size]添加一些任意参数,则不会出现任何类型错误。如何使Typescript意识到这一点?

1 个答案:

答案 0 :(得分:1)

您只需将一些类型参数添加到函数中即可捕获所传递的实际参数类型,从而获得所需的行为。

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
    ])
}

如果您要做的只是在此版本中转发参数,可能会使事情变得更容易:

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是完全类型安全的,如果将鼠标悬停在函数上,则会获得参数名称的工具提示,但在实际代码完成时则不会(此信息将来会修复)。