You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:27:09