Reputation: 30528
I have this code and I was wondering if I can transform the below pipe
s into just one pipe
?
const result: TE.TaskEither<DataTransferError, readonly CoinMetadataDto[]> = pipe(
this.ensureFundsExist(),
TE.chain((funds) => {
return pipe(
funds.map((fund) => {
return this.coinGeckoAdapter.getCoinMetadata(fund.coinGeckoId);
}),
TE.sequenceArray,
);
}),
);
In other words can I map
a TaskEither<E, Data[]>
into a TaskEither<E, OtherData[]>
in one go?
Upvotes: 1
Views: 829
Reputation: 14098
Instead of using Array.prototype.map
(funds.map
), you can use the curried map
from the ReadonlyArray
fp-ts module. Combine this with flow
(left-to-right function composition) and you can get rid of the nested pipe
:
import * as RA from 'fp-ts/ReadonlyArray'
const result: TE.TaskEither<DataTransferError, readonly CoinMetadataDto[]> = pipe(
this.ensureFundsExist(),
TE.chain(
flow(
RA.map(fund => this.coinGeckoAdapter.getCoinMetadata(fund.coinGeckoId)),
TE.sequenceArray
)
)
);
However, there’s an even better way of doing this using traverseArray
:
export declare const traverseArray: <A, B, E>(
f: (a: A) => TaskEither<E, B>
) => (as: readonly A[]) => TaskEither<E, readonly B[]>
TE.traverseArray(f)
is equivalent to flow(RA.map(f), TE.sequenceArray)
.
const result: TE.TaskEither<DataTransferError, readonly CoinMetadataDto[]> = pipe(
this.ensureFundsExist(),
TE.chain(
TE.traverseArray(fund =>
this.coinGeckoAdapter.getCoinMetadata(fund.coinGeckoId)
)
)
);
For more information, have a look at the Traversable
type class.
Upvotes: 2