fp-ts 如何处理不同权限类型的多个 Either
fp-ts How to Handle Multiple Eithers with Different Right Types
当 Either
的右侧没有很好地对齐时,处理 Promise
和 Either
的最佳方法是什么?在这种情况下,我有三个非依赖的“先决条件”操作,表示为 Either
s(具有不同的右手类型)。如果他们都成功了,我不想进行第四次手术。如果三个都失败了,我不想再进行第四个手术了。
至此,我有一个正在编译的解决方案,但对可读性不满意。在这种情况下,肯定有更优雅的方法来处理多个 Either
吗?
//promise of Either<ApiError, CustomerDTO>
const customer = this.customerService.createCustomer(siteOrigin, createCustReq);
//promise of Either<ApiError, LocationDTO>
const location = this.locationService.getRetailOnlineLocation(siteOrigin);
//promise of Either<ApiError, StationDTO>
const station = this.stationService.getRetailOnlineStation(siteOrigin);
//execute previous concurrently
const locationAndStationAndCustomer = await Promise.all([location, station, customer]);
const locationE = locationAndStationAndCustomer[0];
const stationE = locationAndStationAndCustomer[1];
const customerE = locationAndStationAndCustomer[2];
//How to make this better?
const stationAndLocationAndCustomer = E.fold(
(apiErr: ApiError) => E.left(apiErr),
(location: LocationDTO) => {
return E.fold(
(apiErr: ApiError) => E.left(apiErr),
(station: StationDTO) =>
E.right(
E.fold(
(err: ApiError) => E.left(err),
(customer: CustomerDTO) =>
E.right({ location, station, customer })
)(customerE)
)
)(stationE);
}
)(locationE);
我认为评论已经接近正确答案了。 sequenceT
是解决此类问题的正确方法。
import { sequenceT } from 'fp-ts/Apply'
import * as E from 'fp-ts/Either';
const seq = sequenceT(E.Apply);
return pipe(
await Promise.all([location, station, customer]),
seq, // [Either<...>, Either<...>, Either<...>] => Either<ApiError, [...]>
// map is a bit less cumbersome. If the value was Left it returns Left
// otherwise it calls the function which returns a new Right value from
// what the function returns
E.map(([loc, sta, cust]) => ({
location: loc,
station: sta,
customer: cust,
})),
);
当 Either
的右侧没有很好地对齐时,处理 Promise
和 Either
的最佳方法是什么?在这种情况下,我有三个非依赖的“先决条件”操作,表示为 Either
s(具有不同的右手类型)。如果他们都成功了,我不想进行第四次手术。如果三个都失败了,我不想再进行第四个手术了。
至此,我有一个正在编译的解决方案,但对可读性不满意。在这种情况下,肯定有更优雅的方法来处理多个 Either
吗?
//promise of Either<ApiError, CustomerDTO>
const customer = this.customerService.createCustomer(siteOrigin, createCustReq);
//promise of Either<ApiError, LocationDTO>
const location = this.locationService.getRetailOnlineLocation(siteOrigin);
//promise of Either<ApiError, StationDTO>
const station = this.stationService.getRetailOnlineStation(siteOrigin);
//execute previous concurrently
const locationAndStationAndCustomer = await Promise.all([location, station, customer]);
const locationE = locationAndStationAndCustomer[0];
const stationE = locationAndStationAndCustomer[1];
const customerE = locationAndStationAndCustomer[2];
//How to make this better?
const stationAndLocationAndCustomer = E.fold(
(apiErr: ApiError) => E.left(apiErr),
(location: LocationDTO) => {
return E.fold(
(apiErr: ApiError) => E.left(apiErr),
(station: StationDTO) =>
E.right(
E.fold(
(err: ApiError) => E.left(err),
(customer: CustomerDTO) =>
E.right({ location, station, customer })
)(customerE)
)
)(stationE);
}
)(locationE);
我认为评论已经接近正确答案了。 sequenceT
是解决此类问题的正确方法。
import { sequenceT } from 'fp-ts/Apply'
import * as E from 'fp-ts/Either';
const seq = sequenceT(E.Apply);
return pipe(
await Promise.all([location, station, customer]),
seq, // [Either<...>, Either<...>, Either<...>] => Either<ApiError, [...]>
// map is a bit less cumbersome. If the value was Left it returns Left
// otherwise it calls the function which returns a new Right value from
// what the function returns
E.map(([loc, sta, cust]) => ({
location: loc,
station: sta,
customer: cust,
})),
);