Working with loops
Author: FunctionDJCreated May 18, 2026Updated May 18, 2026
I struggly a lot converting a code base to using neverthrow in places where functions are called inside of loops.
Example:
function damageUnitsOnCityTiles(player) {
for (const unit of player.team.getEnemyUnits()) {
if (unit.getTile().type === "city") { // <-- previously, getTile() used throw, but now it returns Result<Tile, E>, so this code expectedly errors
unit.damageUnit(3)
}
}
}How do I rewrite such code to hand over any error upwards? In this example I'd prefer aborting early if an error is encountered and returning it (no need to try all calls and collect all errors).
One possible solution (I think) using safeTry():
function damageUnitsOnCityTiles(player) {
return safeTry(function* () {
for (const unit of player.team.getEnemyUnits()) {
const tile = yield* unit.getTile() // eslint-plugin-neverthrow error: Result must be handled with either of match, unwrapOr or _unsafeUnwrap.
if (tile.type === "city") {
unit.damageUnit(3)
}
}
return ok()
})
}Cons: Lint error + i don't really like generators
Another solution using Result.combine():
function damageUnitsOnCityTiles(player) {
const unitsAndTilesResult = Result.combine(
player.team.getEnemyUnits().map((unit) => unit.getTile().map((tile) => ({ unit, tile }))),
);
return unitsAndTilesResult.map((unitsAndTiles) => {
for (const { unit, tile } of unitsAndTiles) {
if (tile.type === "city") {
unit.damageUnit(3)
}
}
});
}Pros: No lint error
Cons: No abort-early + very boilerplate-y with the unitsAndTilesResult bag variable
Source: supermacro/neverthrow