node.js - 类型可以被promsified的函数
问题描述
我正在努力向node-vagrant NPM 库添加单独的类型以在 Typescript 中使用,以在 DefinitiveTyped 下贡献。但是,库的方法之一是promisify,它使库中的所有其他函数返回一个承诺而不是回调。
鉴于我只能控制添加键入(.d.ts
)文件,有没有办法表明tsc
调用该自定义 promisify 函数的结果是在函数上,或者是其他一些动态机制?或者只是我为函数的两种用法提供了类型,而用户必须确保他们选择正确?
一个最小的例子是 JS 文件是:
module.exports.foo = function (cb) {
cb(null, 'foo');
};
module.exports.promisify = function () {
module.exports.foo = util.promisify(module.exports.foo);
}
我的打字(在.d.ts
文件中)是:
export function foo(cb: (err: null | string, out: string) => void): void;
export function promisify(): void;
现在,当我使用打字时:
import foo = require('foo');
foo.foo((err, out) => { console.log(err, out); });
foo.promisify();
foo.foo().then(out => console.log(out)).catch(err => console.log(err));
最后一行在 TSC 中引发错误。解决方案是在函数签名上同时声明回调和承诺,并让最终用户适当地决定使用哪一个,或者 TypeScript 中是否有某种机制来动态切换函数的返回信息?
综上所述,最后的判决只是在做:
export function foo(): Promise<string>;
export function foo(cb: (err: null | string, out: string) => void): void;
并且如上所述,只是让最终用户弄清楚他们想要回调还是承诺?
解决方案
鉴于我只能控制添加键入(
.d.ts
)文件,有没有办法表明tsc
调用该自定义 promisify 函数的结果是在函数上,或者是其他一些动态机制?
据我所知,这对于 TypeScript 是不可能的。的类型foo
是静态的,虽然 TypeScript 进行了一些基于控制流的类型分析,但它不能foo
使用函数调用来切换类型。
如果promisify()
返回一个包含承诺函数的新对象而不是就地切换它们,那么为此创建准确的类型定义会容易得多。但是由于您无法控制源,我看到的唯一两个选项是:
重载
这是您在问题中已经提到的解决方案。通过为每个方法声明两个签名,所有用法都将是有效的,但用户有责任确保他们promisify
在想要使用 Promise 时调用。
export function foo(): Promise<string>;
export function foo(cb: (err: null | string, out: string) => void): void;
联盟
或者,整个模块可以导出一个联合类型,要求消费者在使用承诺的 API 之前对其进行转换。它可能看起来像这样:
export interface CallbackFoo {
foo(cb: (err: null | string, out: string) => void): void;
promisify(): void;
}
export interface PromiseFoo {
foo(): Promise<string>;
promisify(): void;
}
declare const _: CallbackFoo | PromiseFoo;
export default _;
以及用法:
import foo, { PromiseFoo } from 'foo';
foo.foo((err, out) => { console.log(err, out); });
foo.promisify();
(foo as PromiseFoo).foo().then(out => console.log(out)).catch(err => console.log(err));
现在您可能不想在使用它时一直投射它。一个更简洁的解决方案可能是创建一个单独的文件来导入foo
、调用promisify
和导出它:
import foo, { PromiseFoo } from './foo';
foo.promisify();
export default foo as PromiseFoo;
然而,这当然必须站在最终用户的一边。
推荐阅读
- c# - 如何在 WCF 中仅在一个端点设置授权
- node.js - 通过 npm 包共享 mongoose 模型
- android-broadcast - SDK api 级别低于 24 的 CameraX ImageCapture
- zsh - Zsh 从文件中读取填充关联数组导致奇怪的分离
- sql - 在当前行和上一行之间的范围内加入
- javascript - 如何获取号码,显示在外部网站上?
- javascript - 如何从控制台获取子元素的文本
- mediarecorder - Google 通过 MediaRecorder API 满足流媒体需求
- laravel - 使用 RouteServiceProvider.php 时注入模型中没有数据
- mysql - 自动检查 mysql 授权的方法