typescript - fp-ts 如何处理管道内的异步操作

标签 typescript fp-ts

我正在学习 fp-ts,想知道如何更好地组织我的函数以避免嵌套折叠。我在网上看到的所有示例都有一个很好的简化的管道函数调用,但我不知道如何避免嵌套折叠。

一些上下文 - 在较高级别上,此代码的目的是创建一个位置,如果成功,则创建一个。如果任一操作失败,则向调用者返回适当的错误。如果一切顺利,则返回 201。

public async initialize(
    @requestParam('site') site: string,
    @request() req: Request,
    @response() res: Response
  ) {
    //use the same value for now
    const nameAndPublicId = LocationService.retailOnlineLocationName(site);
    
    const location: E.Either<ApiError, LocationDTO> = await this.locationService.createLocation(
      site,
      nameAndPublicId,
      nameAndPublicId
    );

    const stationName: string = StationService.retailOnlineStationName(site);

    pipe(
      location,
      E.fold(
        (err: ApiError) => ConfigController.respondWithError(err, res),
        async (loc: LocationDTO) => {
          pipe(
            await this.stationService.createStation(site, stationName, loc.id),
            E.fold(
              (err: ApiError) => ConfigController.respondWithError(err, res),
              (_: StationDTO) => res.status(201).send()
            )
          );
        }
      )
    );
  }

  static respondWithError(err: ApiError, res: Response) {
    res.status(err.statusCode).json(err);
  }

最佳答案

想象一下我们正在与 Promise 合作,代码会是什么样子?您将使用 .then 链接所有好的案例处理代码。 ,并且仅附加一个带有最终 .catch 的坏情况处理程序.

public async initialize(
  @requestParam('site') site: string,
  @request() req: Request,
  @response() res: Response
) {
  const stationName: string = StationService.retailOnlineStationName(site);

  const nameAndPublicId = LocationService.retailOnlineLocationName(site);
  
  // for illustration purpose, we suppose here
  // the service returns a Promise of actual value
  // instead of Promise of Either
  await this.locationService.createLocation(
    site,
    nameAndPublicId,
    nameAndPublicId
  ).then((loc: LocationDTO) => {
    return this.stationService.createStation(site, stationName, loc.id)
  }).then((_: StationDTO) => {
    res.status(201).send()
  }).catch(err => {
    ConfigController.respondWithError(err, res),
  })
}

fp 版本应该具有相同的结构,只是类型不同。我们可以使用TaskEither输入模型 a Promise .

public async initialize(
  @requestParam('site') site: string,
  @request() req: Request,
  @response() res: Response
) {
  const stationName: string = StationService.retailOnlineStationName(site);

  const nameAndPublicId = LocationService.retailOnlineLocationName(site);
  
  // here the service shall return Promise of Either
  const createLocationTask = () => this.locationService.createLocation(
    site,
    nameAndPublicId,
    nameAndPublicId
  )

  const chainedTask = pipe(
    createLocationTask,
    TE.fold(
      TE.throwError, // pass through error
      (loc: LocationDTO) => async () => stationService.createStation(site, stationName, loc.id),
    ),
    TE.fold(
      // catch error
      (err: ApiError) => async () => ConfigController.respondWithError(err, res),
      (_: StationDTO) => async () => { res.status(201).send() },
    )
  )

  await chainedTask()
}

附件是带有 stub 的 ts Playground 演示。

TS Playground

关于typescript - fp-ts 如何处理管道内的异步操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68992182/

相关文章:

typescript - 编写一个带有导入子路径 typescript 选项的包

Javascript,异步问题所需的解决方案

typescript :如何 kleisli compose (monadic compose) Promise monad using fp-ts

fp-ts - FP-TS 的 IO 消耗

javascript - 使用 fp-ts 删除 Either 数组中的重复项

javascript - 用 typescript 迭代 map 不起作用

angular - 在 Typescript/Angular2 中显示 bootbox 警报?

javascript - React.js import 语句找不到模块

fp-ts - (已解决) 如何在 FP-TS 中链接依赖的 TaskEither 操作

fp-ts 返回从任一 [] 序列的所有左值