Skip to content

How to best emulate Rust's ? operator? #183

@bluenote10

Description

@bluenote10

I assume you are familiar with ? operator in Rust? I'm wondering what is the best way to achieve something similar with neverthrow's ResultAsync.

REST APIs often require to execute a chain of requests that depend on each other, i.e., I cannot spawn them independently but need to await a successful result sequentially. In case of an error, I want to translate the error into a different error type. Here's an example:

type ResponseType = {
  some: {
    nested: {
      field: number
    }
  },
  other: {
    nested: {
      field: number
    }
  }
}

async function exampleRequest(arg?: number): Promise<ResponseType> {
  return Promise.resolve({
    some: {nested: {field: 1}},
    other: {nested: {field: 2}},
  });
}

function wrap<T>(promise: Promise<T>): ResultAsync<T, Error> {
  return ResultAsync.fromPromise(promise, (e) => e as Error);
}

async function requestChain(): Promise<Result<number, string>> {

  let aResult = await wrap(exampleRequest())
  if (aResult.isErr()) {
    return err("something went wrong in request A")
  }
  let a = aResult.value.some.nested.field

  let bResult = await wrap(exampleRequest(a))
  if (bResult.isErr()) {
    return err("something went wrong in request B")
  }
  let b = bResult.value.other.nested.field

  let cResult = await wrap(exampleRequest(b))
  if (cResult.isErr()) {
    return err("something went wrong in request C")
  }
  let c = cResult.value.other.nested.field

  return ok(a + b + c)
}

It looks like I'm looking for some kind of unwrapOrReturnError. In Rust such chains simplify a lot when using the ? operator. Any thoughts what would be a nice solution with neverthrow?

I feel simply using map doesn't scale so well, because each request would add a level of indentation (in the specific API case I had a chain of 8 requests). Using andThen seems tricky as well, because the steps have complex interdependencies, e.g. I would need the results of step 3+4 in step 7, but step 1+3 in step 8 or so.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions