typescript - TypeScript 构建类似 Promise.all 的函数 - 重载签名与函数实现不兼容
问题描述
通过使用 TypeScript,任何人都sequentially
应该被强制传递 1 到 N 个参数,输入Promise<T>
等于输出[Promise<T>,..
[不工作]当以下列方式重载时,我在第一个声明中遇到 tslint 错误:
重载签名与函数实现不兼容。ts(2394)
promise.ts
function sequentially<T1>(promiseWrappers: [
() => Promise<T1>
]): Promise<[T1]>;
async function sequentially<T1, T2>(promiseWrappers: [
() => Promise<T1>,
() => Promise<T2>
]): Promise<[T1, T2]> {
const resolved = [];
for (const wrapper of promiseWrappers) {
resolved.push(await wrapper());
}
// @ts-ignore
return resolved;
}
[工作]似乎唯一可行的方法是使用.js
单独的声明文件编写实现.d.ts
,如下所示:
promise.js
export async function sequentially(promiseWrappers) {
const resolved = [];
for (const wrapper of promiseWrappers) {
resolved.push(await wrapper());
}
return resolved;
}
promise.d.ts
export declare function sequentially<T1, T2>(promiseWrappers: [
() => Promise<T1>,
() => Promise<T2>
]): Promise<[T1, T2]>;
export declare function sequentially<T1, T2, T3>(promiseWrappers: [
() => Promise<T1>,
() => Promise<T2>,
() => Promise<T3>
]): Promise<[T1, T2, T3]>;
如何修复第一个 TS 实施案例?
解决方案
在 TypeScript 中实现重载函数有一些规则:
调用站点不考虑实现签名,它仅用于对实现进行类型检查(在手册中记录重载的段落末尾提到)
实现签名必须具有与所有重载签名声明兼容的参数。实际上,这意味着每个参数类型必须是来自该参数位置的所有重载的所有参数类型的联合类型。
实现签名必须具有返回类型,该类型是所有重载的返回类型的交集。在实践中,这意味着实现必须在每个 return 语句中对该类型进行类型转换,或者只是将实现返回类型声明为 any。
我在任何地方都找不到 2 和 3 的文档,但它们遵循函数类型兼容性的一般变化规则以及实现签名必须与所有重载声明兼容的事实。
这是代码,它编译--strictFunctionTypes
并--noImplicitAny
打开
function sequentially<T1>(promiseWrappers: [
() => Promise<T1>
]): Promise<[T1]>;
function sequentially<T1, T2>(promiseWrappers: [
() => Promise<T1>,
() => Promise<T2>,
]): Promise<[T1, T2]>;
async function sequentially<T1, T2>(promiseWrappers: [
() => Promise<T1>,
] | [
() => Promise<T1>,
() => Promise<T2>
]): Promise<[T1, T2] & [T1]> {
const resolved = [] as unknown as [T1, T2] & [T1];
for (const wrapper of promiseWrappers) {
resolved.push(await wrapper());
}
return resolved;
}
推荐阅读
- javascript - 带有字符串 arrry 的数组对象中的内部字符串数组过滤器
- python - 如何检查一行中的条目是否出现在另一行中但列值的顺序发生了变化?
- unit-testing - 手动通过声纳云中的“缺失测试”
- laravel - 使用 constrained() 方法时在 Laravel 迁移中为外键指定名称
- reactjs - 如何使用 React-Bootstrap 和 Redux 显示/隐藏 Modal?
- angular - 在生产中的科尔多瓦插件中使用带有离子的 FileReader 时出错
- python - 引用大型 JSON 文件的部分内容
- c# - FirebaseMessaging.TokenReceived 永远不会被触发
- radio-button - 聚合物键盘快捷键干扰单选按钮上现有的输入功能
- flutter - Flutter 自定义表情符号选择器