我有一个内存缓存函数,您可以向该函数传递一个函数及其参数,该函数将缓存结果.函数本身可以工作,但我不知道如何创建泛型类型签名,以便在使用函数而不是函数所需的参数调用缓存时出现错误.下面是一个最小的例子:

type AnyFunc = (...args: any[]) => any;

type MemCache<T extends AnyFunc> = {
  (fn: T, ...args: Parameters<T>): ReturnType<T>;
  debug: () => void;
};

function makeCache<T extends AnyFunc>(): MemCache<T> {
  const cache = {};

  function queryCache<T extends AnyFunc>(fn: T, ...args: Parameters<T>): ReturnType<T> {
    return fn(...args)
  }

  queryCache.debug = () => {
    console.log(cache)
  };

  return queryCache;
}

const memcache = makeCache()

const fn = (num: number, str: string) => 'hello'

//@ts-expect-error
const res = memcache(fn) // should error because 3 arguments are expected but received 1

//@ts-expect-error
res.then() // should error because fn returns a string, not a promise

你也可以在typescript playground中看到这个例子.

我已经try 提取内部函数(queryCache),并按预期分别调用该函数和编译器错误.问题似乎出在外部函数上,但我需要它,因为在加载模块以实例化queryCache函数关闭的缓存时会调用该函数.

推荐答案

这里的主要问题是MemCache中的generic类型参数T的作用域不正确.您已经在顶层将其应用于整个MemCache类型,而它实际上只属于调用签名:

type MemCache = {
  <T extends AnyFunc>(fn: T, ...args: Parameters<T>): ReturnType<T>;
  debug: () => void;
};

关于这些东西为什么会有不同之处的详细描述,请参见typescript difference between placement of generics arguments.简而言之,您希望MemCache能够处理caller想要的任何T,而不仅仅是MemCache中的implementer所 Select 的特定的T.不管怎样,现在makeCache()看起来像

function makeCache(): MemCache {
  const cache = {};

  function queryCache<T extends AnyFunc>(
    fn: T, ...args: Parameters<T>): ReturnType<T> {
    return fn(...args)
  }

  queryCache.debug = () => {
    console.log(cache)
  };

  return queryCache;
}

当你叫它的时候,你会得到你所期望的行为:

const memcache = makeCache()
const fn = (num: number, str: string) => 'hello'
const res = memcache(fn) // err!
// Expected 3 arguments, but got 1
res.then() // err!
// Property 'then' does not exist on type 'string'.

Playground link to code

Typescript相关问答推荐

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

更新:Typescript实用程序函数合并对象键路径

参数类型undefined不能分配给参数类型字符串|未定义

在Typescribe中,extends工作,但当指定派生给super时出错""

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

如何将所有props传递给React中的组件?

部分更新类型的类型相等

TypeScrip泛型类未提供预期的类型错误

从子类集合实例化类,同时保持对Typescript中静态成员的访问

TypeScrip:强制使用动态密钥

为什么我在这个重载函数中需要`as any`?

在React中定义props 的不同方式.FunctionalComponent

RXJS将对键盘/鼠标点击组合做出react

避免混淆两种不同的ID类型

我不明白使用打字脚本在模板中展开参考

接口中可选嵌套属性的类型判断

打字:注解`是字符串`而不是`布尔`?

Karma Angular Unit测试如何创建未解析的promise并在单个测试中解决它,以判断当时的代码是否只在解决后运行

对象只能使用 Typescript 中另一个对象的键