【问题标题】:Narrowing generic function parameters for methods in a nested object缩小嵌套对象中方法的泛型函数参数
【发布时间】:2021-09-25 06:47:43
【问题描述】:

我正在尝试编写一个通用函数,它将下面示例 api 的键作为第一个参数,嵌套对象的方法名称作为第二个参数,该方法的参数作为第三个参数

const api = {
    message: {
        post(message: string) {
            return 'success'
        }
    },
    events: {
        get(id: number) {
            return ['event']
        }
    }

}

我可以根据第一个参数中给出的键来缩小方法范围,如下所示:

type API = typeof api;

function createRequest<T extends keyof API, K extends keyof API[T]>(key: T, method: K) {

}

现在,如果我尝试调用该函数,在将“消息”作为第一个参数传递后,Typscript 将只允许我将“帖子”作为第二个参数传递。到目前为止,一切都很好。但是当我尝试将方法的参数缩小为 createRequest 函数的第三个参数时,我遇到了困难,我尝试了看起来合乎逻辑的方法:

function createRequest<T extends keyof API, K extends keyof API[T]>(key: T, method: K, params: Parameters<API[T][K]>[0]) {

}

Typescript 显示 API[T][K] 的错误,并且似乎不满意 K 确实是 API[T] 的 key - 它显示例如:

Type 'API[T][string]' is not assignable to type '(...args: any) => any

我真的找不到相关的答案,所以任何帮助将不胜感激!

【问题讨论】:

  • 您可能想知道为什么我需要这样做 - 为什么不直接调用函数!?更大的图景是我正在设置一个用于进行 API 调用的 redux 中间件。我想让中间件通用并让它监视单个调度操作,其有效负载包含在发出 api 请求之前要做什么的说明,要发出什么 api 请求和传递给它的参数,以及要做什么处理 api 调用的结果。所以这是构建以 api 方法和参数作为有效负载的动作创建器的第一步

标签: typescript


【解决方案1】:

对我来说,这似乎是编译器的一个怪癖,甚至可能值得提出一个 github 问题。出于某种原因,ParametersT 的类型参数限制似乎正在扩大索引类型。

如果您摆脱它,那么它会按预期工作。我认为您也不会在类型安全方面失去任何东西,因为尝试访问非函数仍然会使其无法调用:

const api = {
  message: {
    post(message: string) {
      return "success";
    },
  },
  events: {
    get(id: number) {
      return ["event"];
    },
    noFunc: 42,
  },
};

type API = typeof api;

type WideParameters<T> = T extends (...args: infer P) => any ? P : never;

function createRequest<T extends keyof API, K extends keyof API[T]>(
  key: T,
  method: K,
  params: WideParameters<API[T][K]>[0],
) {
  return {} as any;
}

createRequest("events", "get", 1); 
  // OK
createRequest("events", "noFunc"); 
  // An argument for 'params' was not provided.
createRequest("events", "noFunc", "") 
  // Argument of type 'string' is not assignable to parameter of type 'never'.

【讨论】:

  • 要完成您的答案,您可以添加type Return&lt;T&gt; = T extends (...args: any[]) =&gt; infer R ? R : never; 并使createRequest 的返回类型类似于Return&lt;API[T][K]&gt;
猜你喜欢
  • 1970-01-01
  • 2019-03-10
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 2019-07-30
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
相关资源
最近更新 更多