Leveraging characteristics of combined types

Can anyone help me understand how to work with union and generic types by re-implementing something similar to Either or Option? Here is the code I have:

type Error = {
  readonly _tag: 'error';
  status: number;
  statusText: string;
};

type Success<T> = {
  readonly _tag: 'success';
  response: T;
};

type PossibleError<T> = Error | Success<T>;

const isSuccessful = <T>(p: PossibleError<T>) => p._tag === 'success';

function fold<T>(
  onSuccess: (e: Success<T>) => void,
  onError: (a: Error) => void
): (pe: PossibleError<T>) => void {
  return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
}

Unfortunately, I encountered the following error:

error TS2339: Property 'response' does not exist on type 'PossibleError<T>'.
  Property 'response' does not exist on type 'Error'.

   return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
                                                   ~~~~~~~~
error TS2345: Argument of type 'PossibleError<T>' is not assignable to parameter of type 'Error'.
  Type 'Success<T>' is missing the following properties from type 'Error': status, statusText

   return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));

I am struggling to make TypeScript understand the type of pe based on my isSuccessful function. How can I access the right parts of my data structure to work with them effectively?

I reviewed the fp-ts implementation of either and noticed they use .left and .right, so I'm not sure what is different in my code.

Answer №1

You're almost there! But there are two issues:

  1. Make sure to include p is Success<T> in your type guard function

     const isSuccessful = <T>(p: PossibleError<T>): p is Success<T> => p._tag === 'success';
     // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^
    
  2. It seems you are passing pe.response instead of just pe to the onSuccess function, whereas onSuccess expects a Success<T> instead of just T. You can either adjust the type of onSuccess:

     function fold<T>(
       onSuccess: (e: T) => void,
     // −−−−−−−−−−−−−−^
       onError: (a: XError) => void
     ): (pe: PossibleError<T>) => void {
       return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
     }
    

    Playground link

    ...or simply pass pe itself:

     function fold<T>(
       onSuccess: (e: Success<T>) => void,
       onError: (a: XError) => void
     ): (pe: PossibleError<T>) => void {
       return pe => (isSuccessful(pe) ? onSuccess(pe) : onError(pe));
     // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^
     }
    

    Playground link


Side note: I've replaced Error with XError in the examples to avoid conflicts with the standard Error function.

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

Setting up jsonServer in gulp with typescript: A guide

Previously, I had set up a json server and used the following code to start it: I found guidance in this GitHub repository. Starting angular2 project with gulp gulp-live-server.js var gulpCore = require('gulp'); var gulpParam = require('g ...

Angular 7 and its scrolling div

Currently, I am working on implementing a straightforward drag and drop feature. When dragging an item, my goal is to scroll the containing div by a specified amount in either direction. To achieve this, I am utilizing Angular Material's CDK drag an ...

primeng allows for implementing a table filter functionality with a dropdown selection

I am working with a p-table from primeng and attempting to synchronize the selection from the dropdown menu with the filter method of the table, but I have not been successful in achieving this. Could you please help me identify the issue? <p-table ...

Steps to display a modal dialog depending on the category of the label

I'm encountering an issue where clicking on different labels should show corresponding modal dialogs, but it always displays the same modal dialog for both labels ("All Recommendations"). Can anyone offer guidance on how to resolve this problem? Thank ...

I'm puzzled as to why my createDoorMethod is returning a string value instead of a number, even though I am passing it a number. Can someone help me

Currently enrolled in a web development course, I am diving into the world of Angular 2 and TypeScript. Despite following along with the video tutorial and using the same code, my implementation is not working as expected, leaving me puzzled. Here is the ...

Angular: Smooth transitions for ngif animations - Learn how to animate ngif elements seamlessly as one element is removed from the DOM

Is there a way to delay the execution of ngIf? I have a scenario where elements in a parent component fade out and are removed from the DOM using ngIf, followed by elements from a child component coming in. However, I am facing an issue with elements overl ...

"Take control of FileUpload in PrimeNG by manually invoking it

Is there a way to customize the file upload process using a separate button instead of the component's default Upload button? If so, how can I achieve this in my code? Here is an example of what I've attempted: <button pButton type="button" ...

The addition operator is not compatible with the given types

Hello, I am currently working on integrating PayPal into an Angular 5 project. The code snippet below shows how I render PayPal buttons using a function: ngAfterViewChecked(): void { if (!this.addScript) { this.addPaypalScript().then(() => { ...

angular 4+ dynamically assign @Input for components created using ngComponentOutlet

If you are using Angular 4 and need to dynamically generate a component, you can utilize the ngComponentOutlet directive. Here is a reference link for more information: https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-directive.html Fo ...

How to refresh a specific component or page in Angular without causing the entire page to reload

Is there a way to make the selected file visible without having to reload the entire page? I want to find a cleaner method for displaying the uploaded document. public onFileSelected(event): void { console.log(this.fileId) const file = event.targe ...

Troubleshooting Problem in Angular 6: Difficulty in presenting data using *ngFor directive (data remains invisible)

I came across a dataset that resembles the following: https://i.sstatic.net/S0YyO.png Within my app.component.html, I have written this code snippet: <ul> <li *ngFor="let data of myData">{{data.id}}</li> </ul> However, when I ...

Utilize Angular roles to sort and organize website data

Exploring the utilization of login roles in my Angular SPA application which operates solely on the client side, integrated with Spring Security and Spring Boot. I have concerns about potential unauthorized access by a skilled developer who could manipula ...

Using Typescript: A guide on including imported images in the output directory

typings/index.d.ts declare module "*.svg"; declare module "*.png"; declare module "*.jpg"; tsconfig.json { "compilerOptions": { "module": "commonjs", "target": "es5", "declaration": true, "outDir": "./dist" }, ...

Guide for implementing props in a text area component using React and TypeScript

My react component has a sleek design: import { TextareaHTMLAttributes} from 'react' import styled from 'styled-components' const TextAreaElement = styled.textarea` border-radius: 40px; border: none; background: white; ` const T ...

Tips for accessing a specific ListItem within the Menu Component using MUI for React

Within my code, I am working with a List that contains multiple ListItems pulled from an array called myCollection. Each ListItem has a MenuIcon element which triggers a menu to appear, providing the option to delete the specific item. Here is a simplified ...

In the search for "action.payload" using Redux Toolkit

const userSlice = createSlice({ name: 'user', initialState, reducers: { // Setting the user setUser: (state, action: PayloadAction<string | null>) => { state.user.email = action.payload; }, setLoading: (state, ...

The Function-supported Operation is having trouble implementing a modification related to Geohash/Geopoint - the Object Type requires a String format

Summary: My function-based Action that tries to set a GeoPoint as a Geohash property is failing with an error suggesting it was anticipating a string. I have an Object Type with a String property that has been designated as a Geohash in the property edito ...

Troubleshooting: Fullscreen Video Autoplay Issue in Angular HTML

Could someone shed some light on why this autoplay video isn't working properly in Chrome? The video is actually hosted in firebase storage. Interestingly, it plays fine when you navigate to a different page and then return to the homepage, but doesn ...

Exploring ways to retrieve checkbox values instead of boolean values upon submission in Angular

I am currently working with a template-driven form and facing an issue. Despite receiving true or false values, I actually need to retrieve the value of checkboxes. <form #f = "ngForm" (ngSubmit) = "onClickSubmit(f.value)"> ...

What could be causing MongoDB to not delete documents on a 30-second cycle?

Having trouble implementing TTL with Typegoose for MongoDB. I am trying to remove a document from the collection if it exceeds 30 seconds old. @ObjectType("TokenResetPasswordType") @InputType("TokenResetPasswordInput") @index( { cr ...