What is the best way to efficiently filter this list of Outcome data generated by neverthrow?

I am working with an array of Results coming from the neverthrow library. My goal is to check if there are any errors in the array and if so, terminate my function. However, the challenge arises when there are no errors present, as I then want to destructure the array into the corresponding Ok types since it's guaranteed that an Err cannot exist at that point.

Let me illustrate the issue with an example:

import { Err, ok, Result } from "neverthrow";

function resultIsError(
  result: Result<unknown, Error>
): result is Err<unknown, Error> {
  return result.isErr();
}

function doSomething() {
  const results = [
    ok(true) as Result<boolean, Error>,
    ok("foobar") as Result<string, Error>,
    ok({ foo: "bar" }) as Result<{ foo: string }, Error>
  ];

  const resultErrors = results.filter(resultIsError);

  if (resultErrors.length > 0) {
    return resultErrors;
  }

  const [someBool, someString, someObj] = results;

  const someBoolValue: boolean = someBool.value;
  const someStringValue: string = someString.value;
  const someObjValue: { foo: string } = someObj.value;
}

The problem surfaces when attempting to access .value, triggering this error message:

Property 'value' does not exist on type 'Err<boolean, Error>'

It seems that Typescript is unable to recognize that Err cannot possibly exist in this scenario. Is there a more elegant and straightforward approach to handle this issue?

To visualize the problem, I have set up a codesandbox: https://codesandbox.io/s/wild-architecture-nivu94?file=/src/index.ts:9-12

Answer №1

Check out the updated example I created to address your concerns here

I will be providing further explanation in this revised answer:

Problem

The error message 'Property 'value' does not exist on type 'Err<boolean, Error>'

Issues at Hand

In your code snippet, you have the following line present

ok(true) as Result<boolean, Error>

This implies that the method ok() is being assigned the type of Result<boolean, Error>. However, according to the types defined in the neverthrow documentation, the type of ok() should be Ok<T, E>

declare type Result<T, E> = Ok<T, E> | Err<T, E>;
declare const ok: <T, E = never>(value: T) => Ok<T, E>;
declare const err: <T = never, E = unknown>(err: E) => Err<T, E>;

The reason for the error lies in the fact that while the value of

ok(true) as Result<boolean, Error>
is Ok<boolean, Error>, its actual type can be either Ok<boolean, Error> or Err<boolean, Error>. Hence, if it turns out to be of type Err<boolean, Error>, it will not contain the property value. This warning from TypeScript highlights this issue

Property 'value' does not exist on type 'Err<boolean, Error>'

Solution

Instead of utilizing Result<boolean, Error>, consider using Ok<boolean, Error>

ok(true) as Ok<boolean, Error>

// or
ok<boolean, Error>(true)  // using ts generic

// recommended approach
ok(true)

Resolution

Specify the types of result explicitly

import { Err, ok, Ok, Result } from "neverthrow";

function resultIsError(
  result: Result<unknown, Error>
): result is Err<unknown, Error> {
  return result.isErr();
}

function doSomething() {
  const results: 
  [
   Ok<boolean, Error>,
   Ok<string, Error>,
   Ok<{ foo: string }, Error>
  ] = [
    ok(true),
    ok("foobar"),
    ok({ foo: "bar" })
  ];

  const resultErrors = results.filter(resultIsError);

  if (resultErrors.length > 0) {
    return resultErrors;
  }

  const [someBool, someString, someObj] = results;
  
  const someBoolValue = someBool.value;
  const someStringValue = someString.value;
  const someObjValue = someObj.value;

  console.log(someBoolValue, someStringValue, someObjValue);
}

doSomething()

Utilize dynamic types for result

import { Err, ok, Result } from "neverthrow";

function resultIsError(
  result: Result<unknown, Error>
): result is Err<unknown, Error> {
  return result.isErr();
}

function doSomething() {
  const results = [ok(true), ok("foobar"), ok({ foo: "bar" })];

  const resultErrors = results.filter(resultIsError);

  if (resultErrors.length > 0) {
    return resultErrors;
  }

  const [someBool, someString, someObj] = results;

  const someBoolValue = someBool.value;
  const someStringValue = someString.value;
  const someObjValue = someObj.value;

  console.log(someBoolValue, someStringValue, someObjValue);
}

doSomething();

Although someBoolValue may appear as a boolean when logged, its possible types could include

string | boolean | { foo: string; }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Monitoring changes within the browser width with Angular 2 to automatically refresh the model

One of the challenges I faced in my Angular 2 application was implementing responsive design by adjusting styles based on browser window width. Below is a snippet of SCSS code showing how I achieved this: .content{ /*styles for narrow screens*/ @m ...

The call to 'setRequestHeader' on 'XMLHttpRequest' was unsuccessful due to the object's state not being OPENED

While developing an angular application with a restful API get(), I encountered a few errors such as unauthorization error:401 which I managed to resolve. However, now I am facing another error that seems quite straightforward. I even tried adding the CORS ...

Handling HTTP Errors in Angular Components with NGRX

I have successfully integrated the store into my angular project. I am able to handle and process the successSelector, but I am facing difficulty in capturing any data with the errorSelector when an HTTP error occurs from the backend. The error is being c ...

Using TypeScript with Angular: encountering a ReferenceError stating that the System object is not defined in the System

I attempted to follow a tutorial to set up Angular 2 with TypeScript from the following link: https://angular.io/guide/quickstart However, I encountered the following error: ReferenceError: System is not defined System.config I am uncertain why this e ...

Struggling to incorporate generics into a Typescript method without sacrificing the typing of object keys

Currently, I am working on a method in Typescript that is responsible for extracting allowable property types from an object of a constrained generic type. The scenario involves a type called ParticipantBase which consists of properties like first: string ...

Sending data to child components in Ionic

I am currently utilizing Ionic's router-outlet to navigate between a parent page and three children pages: parent.page.html <ion-content> <ion-router-outlet></ion-router-outlet> </ion-content> parent-routing-module.page.t ...

A guide on incorporating and utilizing PhotoSwipe in Aurelia / Typescript applications

I've been attempting to integrate PhotoSwipe into my Aurelia project, but I'm struggling to get it working. Within my aurelio.json file under bundles, I've included: { "name": "photoswipe", "path": "../node_modules/photoswipe/dist/ ...

Arranging Objects by Alphabetical Order in Typescript

I am struggling with sorting a list of objects by a string property. The property values are in the format D1, D2 ... D10 ... DXX, always starting with a D followed by a number. However, when I attempt to sort the array using the following code snippet, it ...

Unlocking the Secrets of AnimatedInterpolation Values

I have a question about how to access the value of an AnimatedInterpolation in react-native without resorting to calling private code. To achieve this, I first create an animated value and then wrap it in an interpolation like so: animated = new Anima ...

the ng-repeat directive disables input controls within the tfoot

When working with JSON data, I encountered a situation where I needed to display different types of student details in a table. For one specific type of student, namely partners, I wanted to include input controls such as checkboxes and buttons. However, e ...

Next.js allows for the wrapping of a server component within a client component, seamlessly

I am currently working on a project where I have implemented a form to add data to a JSON using GraphQL and Apollo Client. The project is built with TypeScript and Next.js/React. However, I am facing a conflicting error regarding server client components ...

Is there a program available that can efficiently convert or translate JSON objects into TypeScript types or interfaces?

Can anyone recommend a tool that can easily convert a JSON object into a TypeScript type or interface? An example input would be something like this: I'm hoping to paste the JSON object into the tool and receive an output structure similar to: expor ...

Unable to retrieve dynamically generated object property from an array in AngularJS 2+

Here is an example of an items array: this.itemList = [ { id: 1, name: 'a', address: 'as dasf a' }, { id: 2, name: 'b', address: 'as dasf a' }, { id: 3, name: 'c', address: 'as dasf a' } ]; ...

Enhance the design of MDX in Next.js with a personalized layout

For my Next.js website, I aim to incorporate MDX and TypeScript-React pages. The goal is to have MDX pages automatically rendered with a default layout (such as applied styles, headers, footers) for ease of use by non-technical users when adding new pages. ...

What is the best way to treat each TS file as its own independent module?

Just starting out in the world of TS and feeling like a newbie. I've noticed that in Dart, each file in a directory can run independently and you have to explicitly import objects from other files if needed. For example: file1.dart int myFunc() => ...

What causes a double fill when assigning to a single cell in a 2-dimensional array in Javascript?

I stumbled upon this code snippet featured in a challenging Leetcode problem: function digArtifacts(n: number, artifacts: number[][], dig: number[][]): number { const land: boolean[][] = new Array(n).fill(new Array(n).fill(false)) console.log ...

The parameter cannot be assigned to type 'void' because it is of type 'Promise<unknown>'.ts(2345) - mockReturnValueOnce

Encountering an error while using the mockReturnValueOnce method, specifically 'Argument of type 'Promise' is not assignable to parameter of type 'void'.ts(2345)'. I attempted to solve it by writing the following code: .spyO ...

Creating a responsive class getter with Vue.js 3 using the Composition API: a guide

How can I set up a class instance property to reactively display an error message when authentication fails? UserModel.ts export class User { private error: string; set errorMessage(errorMessage: string) { this.error = errorMessage; } get err ...

Combining class and data within an iteration while utilizing ngFor

I have a dynamic table with rows generated using ngFor <tbody> <tr *ngFor="let item of Details"> <div class="row details-row row-cols-lg-2 row-cols-1" *ngIf="closureDetails"> <div ...

Is it possible to eliminate the table borders and incorporate different colors for every other row?

Eliminating the table borders and applying color to alternate rows. Check out my code snippet: https://stackblitz.com/angular/dnbermjydavk?file=app%2Ftable-overview-example.ts. ...