我正在尝试使用带有es6 promise的TypeScript实现等效于bluebird's Promise.method
。
所需用法:
const stringify = promiseMethod(JSON.stringify)
stringify(/* ... */) //Type checking available here, returns Promise<string>
最近的实施:
const promiseMethod = function<T, U> (fn: (T) => U) {
if (typeof fn !== "function") {
throw new TypeError("Parameter is not a function:" + fn);
}
return <(T) => Promise<U>>function () {
try{
var value = fn.apply(this, arguments);
return Promise.resolve(value);
}
catch (error){
return Promise.reject(error);
}
};
};
上述实现的问题是,当可能有许多参数时,调用站点只需要一个参数。
如果更改参数并将类型返回到Function
,我可以获得可编译的代码,但是参数或返回类型没有类型信息。
答案 0 :(得分:1)
没有办法以100%类型安全的方式执行此操作(AFAIK!如果我错过了某些内容,请指出。)
在一个完美的世界中,Typescript将支持使用类型参数来代表整个参数列表。所以你可以这样做:
function promiseMethod<T,R>(fn: (...args: T) => R) {
但这是不允许的。你能做的最好的是(...args: Array<any>)
,这是非常蹩脚的。
(有关此功能的一些讨论,请参阅github问题here和here。)
您可以采用大锤方法并重载promiseMethod
函数,如下所示:
function promiseMethod<R>(fn: () => R): () => Promise<R>;
function promiseMethod<R,A>(fn: (a: A) => R): (a: A) => Promise<R>;
function promiseMethod<R,A,B>(fn: (a: A, b: B) => R): (a: A, b: B) => Promise<R>;
// etc...
function promiseMethod<R>(fn: (...args: Array<any>) => R) {
// implementation
}
这可能会满足您的需求,但确实存在一些问题:
promiseMethod
,并且那种情况下的输入将会泄漏。fn
本身有重载,也会泄漏(见下文)。仍然,它比...args: Array<any>
更好。许多常用的库(例如lodash)使用这种模式,因为没有更好的替代方案。
如果您传入的功能有重载...祝你好运。 Typescript对函数重载的支持非常浅(by design,似乎)。如果在没有调用它的情况下引用重载函数(例如将其作为回调传递给promiseMethod
函数),编译器似乎只使用最后(?)定义的重载的类型签名,并抛弃其他。不是很好。当然,如果您实际传递重载函数,这只会让您感到厌烦。
最后,我的意见。除非您将大型JS代码库升级为Typescript,否则我会考虑尽可能完全避免使用promisifying模式。特别是现在完全支持async
/ await
(因为TS 2.1),我认为没有用它。