Solve the issue of the __typename union

Imagine having the following union:

export type IBookmarkItemFragment =
  | ({ __typename: "Story" } & {
      story: number;
    })
  | ({ __typename: "Product" } & {
      product: number;
    })
  | ({ __typename: "Project" } & {
      project: number;
    });

You desire to use .filter and .map based on __typeame. For example:

bookmarks
  .filter(bookmark => {
    return bookmark.__typename === "Project";
  })
  .map(project => {
    return project.project;
  });

How can you ensure that in the map, project will always represent:

({ __typename: "Project" } & {
  project: number;
})

Answer №1

To ensure that the function acts as a type guard, you need to explicitly declare it with an annotation:

export type IBookmarkItemFragment =
| ({ __typename: "Story" } & {
    story: number;
    })
| ({ __typename: "Product" } & {
    product: number;
    })
| ({ __typename: "Project" } & {
    project: number;
    });

declare let bookmarks: IBookmarkItemFragment[]
bookmarks
.filter((bookmark):bookmark is Extract<IBookmarkItemFragment, { __typename: "Project"}>   => {
    return bookmark.__typename === "Project";
})
.map(project => {
    return project.project;
});

If you want to have some fun and generalize the type guard, you can create a guard factory that will work for any common tagged union.

export type IBookmarkItemFragment =
| ({ __typename: "Story" } & {
    story: number;
    })
| ({ __typename: "Product" } & {
    product: number;
    })
| ({ __typename: "Project" } & {
    project: number;
    });

function guardFactory<T, K extends keyof T, V extends string & T[K]>(k: K, v: V) : (o: T) => o is Extract<T, Record<K, V>> {
    return function (o: T): o is Extract<T, Record<K, V>> {
        return o[k] === v
    }
}
declare let bookmarks: IBookmarkItemFragment[]
bookmarks
.filter(guardFactory("__typename", "Project"))
.map(project => {
    return project.project;
});

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

Can you explain the concept of "Import trace for requested module" and provide instructions on how to resolve any issues that

Hello everyone, I am new to this site so please forgive me if my question is not perfect. My app was working fine without any issues until today when I tried to run npm run dev. I didn't make any changes, just ran the command and received a strange er ...

Enhance the glowing spinner in a react typescript application

Recently, I transformed an html/css spinner into a react component. However, it seems to be slowing down other client-side processes significantly. You can see the original design on the left and the spinning version on the right in the image below: This ...

What is the best way to display values from a Localstorage array in a tabular format using a looping structure

I have set up a local storage key 'fsubs' to store form submissions as an array. Here is how I am doing it: var fsubs = JSON.parse(localStorage.getItem('fsubs') || "[]"); var fcodes = {"barcodeno" : this.form.value.barcode, "reelno" : ...

The comparison between StrictNullChecks and Union Types in terms of syntax usage

Understanding StrictNullChecks in TypeScript Traditionally, null and undefined have been valid first class type citizens in JavaScript. TypeScript formerly did not enforce this, meaning you couldn't specify a variable to potentially be null or unde ...

Solving Issues with Names, Modules, and Other Strange Elements in Angular Universal

While the main app runs smoothly, attempting to serve the bundled SSR results in perplexing errors that I'm struggling to comprehend. All setup details are provided below for reference. The process of creating a server-side app seems riddled with sma ...

What strategies can be utilized to extract the structure of JSON files imported via a TypeScript asynchronous function?

Examining the example below: export type AppMessages = Awaited<ReturnType<typeof loadMessages>>; export type Locale = "en" | "fr" | "es"; export const loadMessages = async (locale: Locale) => ({ foo: locale ...

Guide on importing npm packages without TypeScript definitions while still enabling IDE to provide intelligent code completion features

I am currently utilizing an npm package that lacks type definitions for TypeScript. Specifically, I'm working with the react-google-maps library. Following their recommended approach, I have imported the following components from the package: import ...

The concept of callback function overloading using generic types in TypeScript

Is there a way to define a callback type in TypeScript that can accept a variable number of generic type arguments while keeping the number of arguments fixed? For instance: export interface CustomFn { <T1>(value1: T1): boolean <T1,T2>(va ...

There was an issue encountered when creating the class: The parameters provided do not correspond to any valid call target signature

I am facing an issue with my code. Here is the scenario: export class MyClass { public name:string; public addr:string; constructor() {} } I have imported MyClass and trying to use it like this: import { MyClass } from './MyClass' ...

Adjusting slidesPerView based on screen size in Ionic: A step-by-step guide

Recently, I encountered an interesting challenge while working on my ionic project. I had successfully created a slider using ion-slides to display multiple products. Everything was working perfectly for the portrait view with 1.25 slides per view (slide ...

Guidelines for declaring types in variable definitions in Typescript

In Typescript, you have multiple options to define a boolean variable such as: let a = true; let b: boolean = true; Given that true is already a boolean value, is it still typical to explicitly declare the variable type (like shown for b)? If yes, does ...

Trouble with styling the Ngx-org-chart in Angular

I integrated the ngx-org-chart library into my Angular project, but I'm facing issues with the styles not applying correctly. Here are the steps I followed: I first installed the package using: yarn add ngx-org-chart Then, I added the ngx-org ...

What could be the reason for SVGR not producing a TypeScript declaration file in my esbuild setup?

I have been working on developing a custom SVG icon library using TypeScript. So far, the SVGR tool has been quite useful in creating components from SVG imports. However, I am encountering an issue with generating types that would allow me to pass attribu ...

Discover how to retrieve service response data from an API and populate it into the Select Option with Angular 2

Api.services.ts getListOfNames() { return this.http.get(this.BaseURL + 'welcome/getnama') .pipe(map(response => { return response; })); } After making the API call, I receive the following resp ...

Is AWS CDK generating nested cdk.out directories during synthesis?

Whilst working on my AWS CDK project for educational purposes, I found myself immersed in learning TypeScript, node.js, npm, and all related concepts simultaneously. Despite the mishap that occurred, requiring me to restart from the Github repository rathe ...

gRPC error: "unable to connect to the specified address" while running a NestJS application on Docker

I am encountering this particular error message when trying to run my NestJS application in a Docker container with gRPC: { "created": "@1616799250.993753300", "description": "Only 1 addresses added ou ...

Unlock the Full Potential of TypeScript: Seamless Export of Classes and Functions

In my AngularJS project, I have a separate JavaScript file where I declare prototype functions. Here's an example: function lastConv(){ this.item1="2" this.message="hello" ...... } lastConv.prototype.setupfromThread(data) { this.currentBox = dat ...

Incorporating a class element within an Angular 2 directive

When working with Angular 2 directives, one way to add an element is by using the following code: this._renderer.createElement(this._el.nativeElement.parentNode, 'div'); After adding the element, how can I set its class and keep a reference to ...

Identifying a shift in data model within a component

It seems like there's a piece I might be overlooking, but here's my current situation - I have data that is being linked to the ngModel input of a component, like so: Typescript: SomeData = { SomeValue: 'bar' } Snippet from the vie ...

Objects vanish 10 seconds after appearing [Angular2, *ngFor]

My Angular2 template is quite straightforward: <span *ngFor="let item of items"> {{ item.description }} </span> Here is the TypeScript logic for it: let list = new Map(); for(let j = 0; j < 100; j++) { list.set(j, { description: j.toS ...