我正在学习 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 演示。
关于typescript - fp-ts 如何处理管道内的异步操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68992182/