typescript - CallableFunction.call 中的“extends keyof”变为“never”
问题描述
下面方法的第二个参数(loadingName
)的类型是第一个参数的key。
(alias) function withLoading<T, P extends keyof T>(this: T, loadingName: P, before: () => Promise<any>): Promise<void>
import withLoading
但是,当我调用时withLoading.call
,类型loadingName
变为never
:
(method) CallableFunction.call<this, [loadingName: never, before: () => Promise<any>], Promise<void>>(this: (this: this, loadingName: never, before: () => Promise<any>) => Promise<...>, thisArg: this, loadingName: never, before: () => Promise<any>): Promise<...>
解决方案
为了将其简化为最小的可重现示例,假设您具有以下功能func
:
declare function func<T>(this: T, key: keyof T): void;
您希望能够按如下方式调用它,但它不起作用:
func.call({ a: 123 }, "a") // error?!
// CallableFunction.call<{ a: number; }, [key: never], void>(...);
为什么?
您正在组合两个泛型函数,并希望编译器可以推断它们之间的高阶关系,以便生成的行为将泛型类型参数从一个函数传播到另一个函数,而无需先指定它们。
这并不是一件完全疯狂的事情,因为 TypeScript 3.4 引入了对泛型函数的高阶类型推断的一些支持,而 TypeScript 3.5 引入了对泛型构造函数的类似支持。
事实上,如果你有一个call()
没有this
参数的独立函数,事情就会如愿以偿:
declare function call<T, A extends any[], R>(
thisArg: T, cb: (this: T, ...args: A) => R, ...args: A): R;
call({ a: 123 }, func, "a") // okay
call({ a: 123 }, func, "b") // error
那么为什么它不能与this
参数一起使用呢?
简短但可能不令人满意的答案是,对高阶函数推理的支持本质上是启发式的,并且在未明确实现的情况下不起作用。如microsoft/TypeScript#30215中所述,实现此支持的拉取请求:
上述算法不是一个完整的统一算法,也不是完美的。
虽然如microsoft/TypeScript#30134中所述的完全统一可能会有所帮助,但它需要对当前在 TypeScript 中的类型推断方式进行相当大的改变,并且可能在编译器性能方面存在问题。无论如何,就目前而言,我们有一个不完美但性能良好的算法。
在研究这个时,我注意到microsoft/TypeScript#33139的存在,这是一个声称使这种推理适用于this
参数的拉取请求。我自己没有测试过,所以我不能确定它是否符合它的要求。虽然它似乎已分配给首席语言架构师,但它已经坐了很长时间没有改变。通常拉取请求应该链接到特定的错误报告或功能请求问题,但我在这里看不到。
那么可以做些什么呢?直接的解决方法是自己手动指定泛型类型参数,如下所示:
func.call<{ a: number }, [key: keyof { a: number }], void>({ a: 123 }, "a"); // okay
不得不这样做并不是很好,但至少编译器可以认识到这种类型参数规范适用于func.call
......这绝对比没有好。换句话说,您不必在这里求助于不安全的类型断言。
从长远来看,您可能想对microsoft/TypeScript#30215发表评论,说明为什么完整的统一算法会改进事情。有人可能还会考虑提交单独的功能请求,以扩展 TypeScript 3.4 对高阶函数的支持以包含this
参数,并在其中链接到microsoft/TypeScript#33139。这些步骤都不能保证对事情何时或是否会改变有任何影响,但它可能不会受到伤害。
推荐阅读
- php - Laravel 在请求验证中使用 config()
- r - 最大灵敏度/特异性与 ROC 曲线之间的关系是什么?
- python - 在 pandas DataFrame 中检查 dtype 时的注意事项
- string - 如何将从文件中读取的数字从str转换为int?
- sql - SQL:计算最后一个相等的值
- node.js - 在 Nexus 中获取最新版本的节点包
- python - 无论如何要在熊猫中重置多索引?
- karma-jasmine - TypeError:无法在打字稿规范文件上读取 null 的属性“长度”
- javascript - Switch 语句默认值始终显示默认值
- python - 导入base64模块后python脚本变慢