typescript - 使用 Function.prototype.bind 时类型谓词丢失
问题描述
TS 3.2.4 对我来说这个错误:
const isArray: typeof Array.isArray = Array.isArray.bind(Array);
错误是
error TS2322: Type '(arg: any) => boolean' is not assignable to type '(arg: any) => arg is any[]'.
Signature '(arg: any): boolean' must be a type predicate.
似乎正在发生的事情是 Array.isArray 的类型谓词在使用 .bind 时丢失了。我测试了几个类型谓词函数,并且总是得到相同的错误。
这是一个真正的 TS 错误,还是我做错了什么?
解决方案
与其说是错误,不如说是设计限制。Typescript 的做法是使用不同数量的参数对其strictBindCallApply
进行多次重载:bind
bind<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T): (...args: A) => R;
bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
bind<T, A0, A1, A2, A3, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
bind<T, AX, R>(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R;
这种方法的问题是类型保护函数返回一个简单的boolean
,它将被捕获R
并转发给返回类型。但是守卫行为没有被捕获或转发R
。它只是被删除了。
虽然可以编写bind
考虑到类型保护行为的函数,但很难获得适用于所有可能排列的版本。
例如,这适用于您的情况:
declare function bind<T, A0, A extends any[], R>(fn: (this: T, arg0: A0 | R, ...args: A) => arg0 is R, thisArg: T): (arg0: A0 | R, ...args: A) => arg0 is R;
const isArray: typeof Array.isArray = bind(Array.isArray, Array);
但这假设受保护的参数是第一个参数,没有什么可以阻止您使用 10 个参数来保护最后一个参数。要捕获这种情况,您需要有一个重载arg0...arg9
(以及介于两者之间的所有重载)。
我将搜索一个问题,但我的猜测是类型系统无法以有效的方式对此进行建模,并且对于这个角落用例来说,使用类型保护版本来拥挤重载是不值得的。
编辑在 GitHub 上找不到错误,您可以发布一个以获得对此事的官方意见,而不仅仅是一个关于 SO 意见的人 :)
推荐阅读
- http - 在 IONIC 3 http.post 请求之间保留会话状态
- python - 如何从 Anaconda 环境(Python 3.7)构建 .exe 程序
- r - 提取R中第2个句点和第3个句点之间的字母
- docker - docker 18.09 版本支持哪个 kubernetes 版本
- c# - 从 XML 文档中将 XML 作为字符串读取
- react-native - 为什么反应原生深度链接到 FB 会打开我的主页而不是我通过的页面
- c - fwrite 目标文件为空后 c 语言
- spring - 使用带有文件的 @PropertySource 注释的 Spring Boot 外部配置
- php - Laravel 5.7 进行身份验证
- powershell - PowerShell 结果转 HTML 报告格式