Original: Generic for type guard functionRewritten: Universal

I have successfully created a function that filters a list of two types into two separate lists of unique type using hardcoded types:

interface TypeA {
  kind: 'typeA';
}
interface TypeB {
  kind: 'typeB';
}
filterMixedList(mixedList$: Observable<(TypeA | TypeB)[]>): Observable<TypeA[]> {
  return mixedList$.pipe(
    map(items => items
      .filter((item): item is TypeA => item.kind === 'typeA')),
  );
}

Is there a way to create a generic solution to avoid hardcoding the types? Any help would be greatly appreciated.

PS: You can find a minimal reproducible example here: stackblitz

Answer №1

To create a more versatile solution, you can pass the type guard function as a parameter. Here's how it would look:

function getTypeFromMixedList<T, U extends T>(
  mixedList$: Observable<T[]>,
  guard: (item: T) => item is U
): Observable<U[]> {
  return mixedList$.pipe(map(items => items.filter(guard)));
}

If you're working with a discriminated union type, you can also provide the discriminant key and value to check for:

function getTypeFromDiscriminatedUnionList<
  T,
  K extends keyof T,
  V extends (T[K]) & (string | number | undefined | null)
>(
  mixedList$: Observable<T[]>,
  key: K,
  val: V
): Observable<Extract<T, { [P in K]?: V }>[]> {
  return mixedList$.pipe(
    map(items =>
      items.filter(
        (item): item is Extract<T, { [P in K]?: V }> => item[key] === val
      )
    )
  );
}

You can use either approach in your specific scenario like this:

getTypeFromMixedList(of([a, b]), (x): x is TypeA => x.kind === "typeA").subscribe(
  v => (dataDivA.innerHTML = JSON.stringify(v))
);

getTypeFromDiscriminatedUnionList(of([a, b]), "kind", "typeB").subscribe(
  v => (dataDivB.innerHTML = JSON.stringify(v))
);

I hope this information proves helpful. Best of luck with your implementation!

Here is the Stackblitz link to the code

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

Dealing with various node types in a parse tree using TypeScript: Tips and Tricks

I am in the process of converting my lexer and parser to TypeScript. You can find the current JavaScript-only code here. To simplify, I have created an example pseudocode: type X = { type: string } type A = X & { list: Array<A | B | C> } ty ...

Tips for displaying bar chart labels effectively with ChartJS

I am working on an Angular project and I would like to incorporate a barchart using ChartJS. The data for this chart can vary in size, sometimes being very large. One issue I have encountered is that when the number of data points is large, the labels ove ...

Updating the text of a Mat-Label dynamically without the need to reload the page

In my application, there is a mat-label that shows the Customer End Date. The end date is fetched initially through a GET request to an API. Let's say the end date is 16-05-2099, which is displayed as it is. There is also a delete button implemented f ...

Trouble implementing array filter in React component is a common issue

Hello everyone! I'm facing an issue with deleting an element from my useState array. I have the index of the element that I want to remove, and I've tried the following code snippet: const updatedArray = myArray.filter((item: any, index: number) ...

Issue with NgOnInit not properly subscribing to observable when using mockActivatedRoute in Jasmine test scenarios

Below is a simple component that I have. All necessary imports should be assumed: //my-component.component.ts //imports, decorator, etc. routingNumber: number; ngOnInit() { this.route.params.subscribe( params => { this.routingNumber = +p ...

How can we initiate an AJAX request in React when a button is clicked?

I'm fairly new to React and I'm experimenting with making an AJAX call triggered by a specific button click. This is how I am currently using the XMLHttpRequest method: getAssessment() { const data = this.data //some request data here co ...

How to Override Global CSS in a Freshly Created Angular Component

My CSS skills are a bit rusty and I need some assistance with a project I'm working on. The project includes multiple global CSS files that have properties defined for different tags, such as .btn. However, these global CSS files are causing conflicts ...

Moving information from two modules to the service (Angular 2)

Recently in my Angular2 project, I created two components (users.component and tasks.component) that need to pass data to a service for processing before sending it to the parent component. Code snippet from users.component.ts: Import { Component } fro ...

Having trouble with reactjs and typescript? Getting the error message that says "Type 'string' is not assignable to type 'never'"?

When trying to setState with componentDidMount after an axios request is completed, you may encounter the error message Type 'string' is not assignable to type 'never'. Below is the code snippet: import * as React from 'react&apos ...

Display an image in an Angular application using a secure URL

I am trying to return an image using a blob request in Angular and display it in the HTML. I have implemented the following code: <img [src]="ImageUrl"/> This is the TypeScript code I am using: private src$ = new BehaviorSubject(this.Url); data ...

Tips for positioning a div alongside its parent div

I have a unique setup with two nested divs that are both draggable. When I move the parent div (moveablecontainer), the child div (box.opened) follows smoothly as programmed. Everything works well in this scenario. However, when I resize the browser windo ...

Angular 5 does not allow function calls within decorators

I encountered an issue while building a Progressive Web App (PWA) from my Angular application. When running ng build --prod, I received the following error: ERROR in app\app.module.ts(108,64): Error during template compile of 'AppModule' Fu ...

Tips for activating automatic building of packages when utilizing pnpm install?

Our unique project is utilizing a combination of pnpm, workspace, and typescript in adherence to the monorepo standard. Upon cloning the repository, we execute a pnpm install command to download dependencies and establish links between local packages. De ...

New Entry failing to appear in table after new record is inserted in CRUD Angular application

Working with Angular 13, I developed a basic CRUD application for managing employee data. Upon submitting new information, the createEmployee() service is executed and the data is displayed in the console. However, sometimes the newly created entry does no ...

NestJS Resolver Problem: Getting an Undefined Error

Could use a bit of assistance. I'm currently working on a mutation and encountering the following error: ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'entryUser') Here is the resolver code snippet: export class Us ...

Exploring the new possibilities of Angular 5: Enhanced REST API service with paginated data and object mapping capabilities

After implementing pagination in my REST API backend, I now need to update my Angular services to accommodate the changes. Instead of simply returning an array of objects, the API will now return JSON responses structured like this: { "count": 0, ...

Using scrollIntoView() in combination with Angular Material's Mat-Menu-Item does not produce the desired result

I am facing an issue with angular material and scrollIntoView({ behavior: 'smooth', block: 'start' }). My goal is to click on a mat-menu-item, which is inside an item in a mat-table, and scroll to a specific HTML tag This is my target ...

How come I am unable to fetch classes and enums from a namespace?

When using Typescript with pg-promise, I am facing an issue where I can't import the classes and enums as I normally would. Typically, when working with a library, I import a type, use it, and everything functions properly. However, in the snippet bel ...

Vue: Defining typed props interface including optional properties

I created a method that I want to be accessible on all my Vue instances, so I can use it in case of an error and display a specific error component. Similar to the functionality provided by vue-error-page. Since I am working with typescript, I now want to ...

Tips on ensuring the callback function is properly called when it is passed as an argument to another function

I am facing a challenge with my typescript method that needs to call another method, on(), which requires a callback method. I want the myConnect() method to wait until the callback is executed. I believe this involves using a promise, but I'm struggl ...