Can we handle optional properties that are contingent on a boolean in the type?

My current scenario involves a server response containing a boolean indicating success and optional data or error information.

type ServerResponse = {
  success: boolean;
  data?: { [key: string]: string };
  err?: { code: number, message: string };
}

Dealing with this type can sometimes feel cumbersome:

const resp: ServerResponse = await fetch(...);

if(resp.success) {
   doSomething( resp.data?.foo );
} else {
   handleErr( resp.err?.message );
}

It can be frustrating having to use the ? operator when I know that data will always exist when success === true, and err will always exist when success === false.

I've tried understanding the mapped types documentation, but it doesn't seem to provide the solution I'm looking for.

Is changing the approach to ignore success the only or best way to address this issue?

const resp: ServerResponse = await fetch(...);

if(resp.data) {
   doSomething( resp.data.foo );
} else if(resp.err) {
   handleErr( resp.err.message );
}

Although this method seems reasonable, I am interested in exploring more advanced typing techniques.

Answer №1

To tackle this scenario, you can utilize union types.

Here is the corresponding code snippet for your specific situation:

interface SuccessResponse {
    success: true;
    data: { [key: string]: string }
}

interface ErrorResponse {
    success: false;
    err: { code: number, message: string };
}

type ServerResponse = SuccessResponse | ErrorResponse;

fetch("http://your-endpoint.com")
    .then((response) => {
        return response.json();
    })
    .then((jsonResponse: ServerResponse) => {
        if(jsonResponse.success) {
            console.log(jsonResponse.data)
        } else {
            console.log(jsonResponse.err)
        }
    })

TS Playground Version

If there are any uncertainties, feel free to reach out.

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

What steps are required to transform a TypeScript class with decorators into a proper Vue component?

When I inquire about the inner workings of vue-class-component, it seems that my question is often deemed too broad. Despite examining the source code, I still struggle to grasp its functionality and feel the need to simplify my understanding. Consider th ...

Creating custom disabled button styles using TailwindUI in a NextJS application

I had a NextJS application that utilized Atomic CSS and featured a button which becomes disabled if a form is left unfilled: <Button className="primary" onClick={handleCreateCommunity} disabled={!phone || !communi ...

Guide on removing a key from an object in TypeScript

My variable myMap: { [key: string]: string[] } = {} contains data that I need to modify. Specifically, I am trying to remove a specific value associated with a certain key from the myMap. In this case, my goal is to delete value1 from myMap[Key1]. Despit ...

Trouble arises when managing click events within the Material UI Menu component

I've implemented the Menu Component from Material UI as shown below - <Menu open={open} id={id} onClose={handleClose} onClick={handleClick} anchorEl={anchorEl} transformOrigin={{ horizontal: transformOriginRight, vertical: t ...

Why is the ionChange/ngModelChange function being triggered from an ion-checkbox even though I did not specifically call it?

I have an issue with my code involving the ion-datetime and ion-check-box. I want it so that when a date is selected, the checkbox should automatically be set to false. Similarly, if the checkbox is clicked, the ion-datetime value should be cleared. Link ...

Does anyone have experience using the useRef hook in React?

Can someone help me with this recurring issue: "Property 'value' does not exist on type 'never'" interface InputProps { name: string; icon?: ReactElement; placeholder?: string; } const Input = ({ name, icon: Icon, ...rest }: Inpu ...

Easy-to-use blog featuring Next.js 13 and app router - MDX or other options available

Currently in the process of transitioning a Gatsby website to Next.js (v13.4) and utilizing the new App Router. However, I'm facing some challenges when it comes to migrating the blog section over because there isn't much accurate guidance availa ...

Adding a dynamic CSS stylesheet at runtime with the power of Angular and Ionic 2

Currently, I am working on creating a bilingual application using Ionic2. The two languages supported are English and Arabic. As part of this project, I have created separate CSS files for each language - english.css and arabic.css. In order to switch be ...

What is the process for creating a unit test case for an Angular service page?

How can I create test cases for the service page using Jasmine? I attempted to write unit tests for the following function. service.page.ts get(): Observable<Array<modelsample>> { const endpoint = "URL" ; return ...

Leveraging AWS SSM in a serverless.ts file with AWS Lambda: A guide to implementation

Having trouble utilizing SSM in the serverless.ts file and encountering issues. const serverlessConfiguration: AWS = { service: "data-lineage", frameworkVersion: "2", custom: { webpack: { webpackConfig: "./webpack ...

The storage does not reflect updates when using redux-persist with next-redux-wrapper in a Typescript project

I'm currently working on integrating redux-persist with next.js using next-redux-wrapper. However, I'm facing an issue where the storage is not updating and the state is lost during page refresh. Below is my store.ts file: import { createStore, ...

Vite HMR causes Vue component to exceed the maximum number of recursive updates

After making changes to a nested component in Vue and saving it, I noticed that the Vite HMR kept reloading the component, resulting in a warning from Vue: Maximum recursive updates exceeded... Check out the online demo on stackblitz. Make a change in Chi ...

Nested validation schema featuring conditional validation - yes, we've got it covered!

In my Formik object, I have set initial values as follows: {customerDetails: {id: "", name: "", mobileNumber: ""}, notes: {id: "", text: "", type: ""}} How can I create a conditional Yup validati ...

Having trouble establishing a connection with the C# Controller when processing the frontend request

Having trouble implementing the Search by siteId functionality using typescript and C#. The issue arises when trying to connect to the C# controller from the frontend request. The parameter I need to pass is siteId. Below is the code snippet: HTML: ...

Obtain the data from a service that utilizes observables in conjunction with the Angular Google Maps API

In my Angular project, I needed to include a map component. I integrated the Google Maps API service in a file called map.service.ts. My goal was to draw circles (polygons) on the map and send values to the backend. To achieve this, I added event listeners ...

I'm experiencing some difficulties utilizing the return value from a function in Typescript

I am looking for a way to iterate through an array to check if a node has child nodes and whether it is compatible with the user's role. My initial idea was to use "for (let entry of someArray)" to access each node value in the array. However, the "s ...

Error: The value of "$tweetId" cannot be parsed as it is set to "undefined". Please ensure that string values are properly enclosed

I am utilizing sanity, and if you require more details, I will furnish it promptly. When I try to access http://localhost:3000/api/getComments, I encounter the following error message: ClientError: Unable to process value of "$tweetId=undefined". Kindly ...

Utilizing the dialogue feature within Angular 6

Situation: I am managing two sets of data in JSON format named customers and workers: customers: [ { "cusId": "01", "customerName": "Customer One", "email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data- ...

Issue with Dates in Typescript array elements

When attempting to compare different Date elements in my code, I encountered an issue. I have two date elements representing date formats but am unable to compare them because I keep receiving the error message "core.js:6237 ERROR TypeError: newticketList. ...

Using a decorator with an abstract method

Discussing a specific class: export abstract class CanDeactivateComponent { abstract canLeavePage(): boolean; abstract onPageLeave(): void; @someDecorator abstract canDeactivateBeforeUnload(): boolean; } An error occurred stating that A decorat ...