Is there a way to retrieve a specific type from a union-based type by using a generic function in Typescript?

When working with my API, I have noticed a consistent pattern where it returns either a specific type or a TypeScript type called BadResult, as shown below:

type Result1 = CreatedPersonResult | BadResult;
type Result2 = CreatedRoleResult | BadResult;

To streamline my code, I am looking to create a generic wrapper function that can accept either Result1 or Result2 as input and return only the successful result, such as CreatedPersonResult.

I believe leveraging the Exclude option in TypeScript might be the solution.

In cases where the result is a BadResult, throwing an error would be acceptable.

const resolveActualType = (result: T): Exclude<T, BadResult> => {    
    // if(... is BadResult) {
    //   throw Error();
    // }
    
    return result;
}

Answer №1

To effectively constrain the generic parameter type in TypeScript and ensure that the result does not match a specific type after error handling, we can utilize union types directly in the function parameter for inference.

Instead of considering the entire union as the generic parameter type T, we can let TypeScript infer it as the part without the specified type (BadResult):

// T is inferred as the type excluding BadResult directly
const resolveActualType = <T,>(result: T | BadResult): T => {
    result
    //^? BadResult | T

    if (isBadResult(result)) {
        result
        //^? BadResult
        throw Error();
    }

    return result;
    //     ^? T
}

declare const r1b: Result1
const r1 = resolveActualType(r1b)
//    ^? CreatedPersonResult

declare const r2b: Result2
const r2 = resolveActualType(r2b)
//    ^? CreatedRoleResult
 | BadResult;

// The actual implementation of the type guard predicate depends on the specific BadResult type
declare function isBadResult(result: unknown): result is BadResult

Playground Link

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

The error message TS2304 is indicating that the name 'Set' cannot be found in electron-builder

I am trying to utilize the AppUpdater feature in electron-builder for my Electron Application. Upon importing the updater in my main.ts file: import { autoUpdater } from "electron-updater" An error is triggered when running the application: node_module ...

What is the best way to create a function that can securely search for a URL containing parameters while ensuring type safety?

I am working on a NextJS/React application. We have a large object containing internal URLs, each with a createPath function that looks similar to this: const URLS = { dashboard: { createPath: ({ accountNumber }: { accountNumber: string }) => ...

Assign a specific value to the sub-component within the grid using Angular 2+

Incorporating Angular 8 and TypeScript into my project, I have a grid that consists of various internal components, one being <ng-select/>. The data binding takes place in the child component during onInit. Upon loading and initialization of the dat ...

Creating a button that displays the current day with Angular

I'm in the process of developing a timetable app that features buttons for the previous day, current day, and next day. How can I implement a button to specifically show the current day? HTML File <button type="button" (click)="previousDay()" ...

Can a TypeScript variable in Angular contain a mixture of HTML and plain text?

I have a website where I am displaying content from a Model file. I would like to create a TypeScript variable that contains both a string related to the website's content and a URL enclosed in an HTML tag. When this variable is rendered on the view, ...

Unable to associate Interface with HTTP response

When I run the following code in Chrome console, I get an error: ERROR TypeError: t.json(...).map is not a function. However, both ng serve -prod and ng test --sm=false work fine. My goal is to map the result to the model in Interface and display it in HT ...

Angular's getter value triggers the ExpressionChangedAfterItHasBeenCheckedError

I'm encountering the ExpressionChangedAfterItHasBeenCheckedError due to my getter function, selectedRows, in my component. public get selectedRows() { if (this.gridApi) { return this.gridApi.getSelectedRows(); } else { return null; } } ...

Error in TypeScript on SendGrid API: Invalid HttpMethod

Here is my code snippet: import sendgridClient from '@sendgrid/client' sendgridClient.setApiKey(process.env.SENDGRID_API_KEY); const sendgridRequest = { method: 'PUT', url: '/v3/marketing/contacts', bo ...

JavaScript - Trouble encountered while trying to use splice to insert one array into another array

I've been working on creating a Cache Hashtable using JavaScript. When I use the code cache.splice(0,0, ...dataPage);, it inserts my data starting from the first position up to the length of dataPage. Assuming that my dataPage size is always 10. Th ...

Sequencing API Calls: A Guide on Making Sequential API Requests

Currently, I am working on mastering RxJS. Within my project, there are 3 API calls that need to be made. Specifically, I must execute the 2nd API call and then pass its data as a parameter to the 3rd API call. My attempt at achieving this functionality is ...

What is the reason this union-based type does not result in an error?

In my TypeScript project, I encountered a situation that could be simplified as follows: Let's take a look at the type Type: type Type = { a: number; } | { a: number; b: number; } | { a: number; b: number; c: number; }; I proceed to defi ...

Breaking up React code within the React.createElement() function

I am encountering an issue with lazily loaded pages or components that need to be rendered after the main page loads. When using createElement(), I receive the following error: LazyExoticComponent | LazyExoticComponent is not assignable to parameter of ty ...

Encountering a challenge in Angular 8: Unable to locate a supporting object matching '[object Object]'

I am having an issue trying to retrieve the Spotify API from the current user's playlists. While I can see it in my console, when I attempt to insert it into HTML, I encounter the following error: ERROR Error: Cannot find a differ supporting object ...

How to stop a checkbox from being selected in Angular 2

I have a table with checkboxes in each row. The table header contains a Check All checkbox that can toggle all the checkboxes in the table rows. I want to implement a feature where, if the number of checkboxes exceeds a certain limit, an error message is ...

Utilizing React MUI Autocomplete to Save Selected Items

Exploring the realms of React and TypeScript, I find myself puzzled by a task at hand. It involves storing user-selected options from an Autocomplete component and subsequently sending these values to an external API. Is there a recommended approach for ac ...

What is the best way to determine a comprehensive map of every sub-store, their functions, and what data they contain?

Summary: Can all actions with their payloads be automatically grouped by sub-store in a composite store using a single type entity (e.g., interface)? I have implemented a Redux store with multiple sub-stores structured as follows: There is an action setA ...

Tips for displaying or concealing a div using Angular Js

I have set up two div elements with a dropdown control in one named div1. I am looking to hide div2 until a value is selected in the dropdown. How can I show or hide a div based on ng-change, ensuring that div2 remains hidden until a value is selected? Cod ...

Exploring the potential of the forkJoin operator in Angular 4's Observable

I'm currently facing a challenge that involves retrieving both administrators and professionals from the "users" collection using AngularFire's latest version. I am utilizing Observables for this task. My goal is to make two parallel requests an ...

How can you limit a type reference to a specific file in TypeScript?

Currently, I am working on writing universal JavaScript code that can be used in both Node and browser environments. While most of the code works independent of the environment, there are certain parts where different implementations are required based on ...

Using the TypeScript compiler API to determine the location in the generated code of a particular AST node

I am aiming to retrieve the specific TypeScript AST node's location (start and end) in the emitted JavaScript file. Consider this code snippet: const program = ts.createProgram(tsconfig.fileNames, tsconfig.options); const aNode = program.getSourceFi ...