TypeScript中如何实现异步Monad的无限链式调用?
解决Response类bindAsync方法链式调用问题
问题原因
你的bindAsync方法返回的是Promise<Response<R>>,而原生Promise对象并没有bindAsync或bind方法,所以第一次调用bindAsync后得到的是一个Promise实例,无法继续链式调用后续的bindAsync,导致报错Property 'bindAsync' does not exist on type 'Promise<Response<...>>'。
解决方案
我们可以创建一个继承自Promise<Response<T>>的AsyncResponse类,在其中实现bind和bindAsync方法,让异步调用后的结果依然支持链式操作。同时补全原Response类中缺失的data()方法(你的示例代码中用到了该方法但未实现)。
修改后的完整代码
type SuccessResponse<T> = [null, T]; type Err = { message: string; stack: string; name: string }; type ErrResponse = [Err, null]; export type HandleResponse<T> = SuccessResponse<T> | ErrResponse; // 封装支持链式调用的异步Response类 class AsyncResponse<R> extends Promise<Response<R>> { bind<NewR>(func: (res: Response<R>) => Response<NewR>): AsyncResponse<NewR> { return new AsyncResponse(async (resolve) => { const res = await this; resolve(res.bind(func)); }); } bindAsync<NewR>(func: (res: Response<R>) => Promise<Response<NewR>>): AsyncResponse<NewR> { return new AsyncResponse(async (resolve) => { const res = await this; resolve(await res.bindAsync(func)); }); } } export class Response<T> { private _data: T | null; private _err: Err | null; private constructor(data: T | null, err: Err | null) { this._data = data; this._err = err; } static success<T>(data: T): Response<T> { return new Response(data, null); } static err<T>(err: Err): Response<T> { return new Response(null, err) as Response<T>; } // 补全示例中用到的data方法 data(): T | null { return this._data; } bind<R>(func: (res: Response<T>) => Response<R>): Response<R> { if (this._err) { return Response.err(this._err) as Response<R>; } return func(this); } // 修改bindAsync返回AsyncResponse,支持链式调用 bindAsync<R>(func: (res: Response<T>) => Promise<Response<R>>): AsyncResponse<R> { if (this._err) { return new AsyncResponse((resolve) => resolve(Response.err(this._err) as Response<R>)); } return new AsyncResponse(async (resolve) => resolve(await func(this))); } divide(): HandleResponse<T> { if (this._data) return [null, this._data]; return [this._err as Err, null]; } }
测试链式调用
现在你的示例代码可以正常执行无限链式调用了:
async function chainingMoreThanOne() { const addTen = async (res: Response<number>) => { const num = res.data() as number; return Response.success(num + 10); }; // 支持无限链式调用 const finalRes = await Response.success(5) .bindAsync(addTen) .bindAsync(addTen) .bindAsync(addTen); console.log(finalRes.data()); // 输出35 } chainingMoreThanOne();
原理说明
AsyncResponse继承自Promise<Response<R>>,所以它可以像普通Promise一样使用await、then、catch等方法。- 我们在
AsyncResponse中实现了bind和bindAsync方法,这些方法会等待当前Promise完成后,再调用对应的Response方法,返回新的AsyncResponse,从而实现链式调用。 - 原
Response类的bindAsync方法不再返回普通Promise,而是返回AsyncResponse,确保第一次调用后依然能继续链式调用。
内容的提问来源于stack exchange,提问作者dvgga
相关产品推荐
相关产品推荐

