Obtain the precise Discriminated conditional unions type in the iterator function with Typescript

export type FILTER_META =
  | {
      type: 'string';
      key: string;
      filters: { id: string; label?: string }[];
    }
  | {
      type: 'time';
      key: string;
      filters: { min: string; max: string  }[];
    }
  | {
      type: 'range';
      key: string;
      filters: { min: number; max: number }[];
    };

 type Unpacked<T> = T extends (infer U)[] ? U : T;
 type Foo = Unpacked<FILTER_META['filters']>;

// how to determine comparer type from meta object
// comparer:Foo doesn't work
// const comparator = <T extends FILTER_META, U extends Unpacked<T['filters']>>(

const comparator = (meta: FILTER_META, item: any, comparer: any) => {
  const DATE_PREFIX = '1/1/2022 ';

  switch (meta.type) {
    case 
      return item?.[meta.key]?.toLowerCase() === comparer.id?.toLowerCase();
    case 'time': {
      const { min, max } = comparer;
      const compTime = new Date(DATE_PREFIX + item?.[meta.key]);
      return (
        new Date(DATE_PREFIX + min) <= compTime &&
        compTime <= new Date(DATE_PREFIX + max)
      );
    }
    case 'range': {
      const { min, max } = comparer;
      const compItem = item?.[meta.key];
      return min <= compItem && compItem <= max;
    }
  }
};


const genericFilter =
  (filterMeta: FILTER_META[]) =>
  (list = []) =>
    list.filter((item) =>
      filterMeta
        .filter((fMeta) => fMeta.filters.length)
        .every((meta) =>
          meta.filters.some((ft: any) => comparator(meta, item, ft))
        )
    );

This is a versatile filtering function that aims to sort an array using various filter types. It receives an assortment of different filters in an array and employs the comparer function to execute the filtering.

How can I specify the type of the third argument comparer:any based on the first argument which is of type FILTER_META

Find the code on Stackblitz via the following link: https://stackblitz.com/edit/typescript-ku6bq7

Answer №1

Ensure that the variable in switch(theValue) is identical to the one being nested into (e.g. theValue.filters.id). By utilizing switch(theValue.type), TypeScript can recognize that the filters of the current theValue are of type "string" rather than "time". In its absence, TypeScript cannot infer if id is a key in comparer since it's uncertain whether comparer is of type "string", "time", or "range". Hence, comparer.id will not be considered valid by TypeScript.

For instance, if fo is specifically defined as: (please note: .filters is not an array)

type fo =  {
  type: 'string';
  key: string;
  filters: { id: string; label?: string }; // not an array (is unpacked")
}
| {
  type: 'time';
  key: string;
  filters: { min: string; max: string }; // not an array (is "unpacked")
}
| {
  type: 'range';
  key: string;
  filters: { min: number; max: number }; // not an array (is "unpacked")
};

then this functionality applies:

const comparator = (meta: FILTER_META, item: any, comparer: fo) => {
  const DATE_PREFIX = '1/1/2022 ';

  switch (comparer.type) {
    case 'string':
      return item?.[meta.key]?.toLowerCase() === comparer.filters.id?.toLowerCase();
    case 'time': {
      const { min, max } = comparer.filters;
      const compTime = new Date(DATE_PREFIX + item?.[meta.key]);
      return (
        new Date(DATE_PREFIX + min) <= compTime &&
        compTime <= new Date(DATE_PREFIX + max)
      );
    }
    case 'range': {
      const { min, max } = comparer.filters;
      const compItem = item?.[meta.key];
      return min <= compItem && compItem <= max;
    }
  }
};

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

Invalid for the purpose of storage

Encountering the following error message: The dollar ($) prefixed field '$size' in 'analytics.visits.amounts..$size' is not valid for storage. return Manager.updateMany({}, { $push: { & ...

Error in Typescript: Property 'timeLog' is not recognized on type 'Console'

ERROR in src/app/utils/indicator-drawer.utils.ts:119:25 - error TS2339: Property 'timeLog' does not exist on type 'Console'. 119 console.timeLog("drawing") I am currently working with Typescript and Angular. I have ...

Creating a stream of observables in RxJs and subscribing to only the latest one after a delay: A comprehensive guide

I am trying to create a stream of Observables with delay and only subscribe to the last one after a specified time. I have three HostListeners in which I want to use to achieve this. I would like to avoid using Observable form event and instead rely on H ...

The useRef function is malfunctioning and throwing an error: TypeError - attempting to access 'filed2.current.focus' when 'filed2' is null

I'm attempting to switch focus to the next input field whenever the keyboard's next button is pressed. After referring to the react native documentation, it seems that I need to utilize the useRef hook. However, when following the instructions f ...

Having difficulty accessing an element within ng-template during the unit test writing process with Jasmine

I am encountering an issue when trying to access a button inside an ng-container in my testing environment. Despite manually setting the value of the ngIf condition to true, the elements inside are not being rendered. Here is what I have attempted so far: ...

Template reference does not connect to the ApexChart graphic

As a newcomer to ApexCharts.js, I am currently working on setting up a Vue3 app using Composition API along with the setup syntax. My goal is to reference the template ref of 'apexchart' so that I can later call the dataURI() function on it. I am ...

Incorporate form information into an array in Angular Version 2 or higher

This form is where I craft my questions https://i.sstatic.net/93781.png When composing a question, the ability to include multiple alternatives is available. There will also be an option to edit these alternatives. The desired format for my array is as ...

Angular 5 offers the capability to use mat-slide-toggle to easily display and manipulate

I am experiencing an issue with displaying data in HTML using a mat-slide-toggle. The mat-slide-toggle works correctly, but the display does not reflect whether the value is 1 (checked) or 0 (unchecked). Can anyone provide some ideas on how to resolve this ...

What is the best method for inserting a hyperlink into the JSON string obtained from a subreddit?

const allowedPosts = body.data.children.filter((post: { data: { over_18: any; }; }) => !post.data.over_18); if (!allowedPosts.length) return message.channel.send('It seems we are out of fresh memes!, Try again later.'); const randomInd ...

Elementary component placed in a single line

Creating a text dropdown menu using the following code: import { Autocomplete, TextField } from '@mui/material' import React, { useState } from 'react' const options = [ 'Never', 'Every Minute', 'Every 2 ...

Guide to retrieving Azure web app application settings in a TypeScript file

I recently created an Angular 2 application using Visual Studio 2015. After that, I successfully published my Angular 2 web app to Azure Web App and everything seems to be working fine. However, I am facing a challenge in accessing the application setting ...

My project in WebStorm encounters a setback due to the updated release of Typescript 5+

Recently, I had to upgrade my TypeScript version from 4.9.5 to 5.1.3 because one of the libraries I'm using made a fix that required a newer TypeScript version. After the update, TypeScript started throwing errors for console calls and React event di ...

Creating formGroups dynamically for each object in an array and then updating the values with the object data

What I am aiming to accomplish: My goal is to dynamically generate a new formGroup for each recipe received from the backend (stored in this.selectedRecipe.ingredients) and then update the value of each formControl within the newly created formGroup with t ...

The JQuery signature does not include the necessary string context

We are in the process of transitioning legacy JavaScript code to TypeScript. In our current codebase, we have jQuery selectors that utilize a string as a context: $("example", "someId"). However, when converting this to TypeScript, the definition file JQu ...

The error message "ReferenceError: window is not defined in Angular Universal" indicates

Currently, I'm utilizing Angular 10 and undergoing the process of incorporating SSR into my project. Upon executing the npm run serve:ssr, I encounter the following error: ReferenceError: window is not defined After conducting a search online, the r ...

Encountered an error trying to access '0' property of an undefined object when iterating through data in angular framework

My API is returning data in the format shown below: "fileName": "data.txt", "onlyInFile1": [ { "_id": "60618e87c2077428e4fedde5", "TERMINAL_ID": "Y6152114", "EXTERNAL_STAN": & ...

Why isn't my Next.js middleware working properly with TypeScript?

My issue arises from the fact that, despite following the documentation, the middleware in Next.js is not functioning as I anticipated. I experimented with what I thought was the simplest middleware possible. I expected that when navigating to /, a conso ...

Combining information through specified parameters

Here is the data I have available: Data <- data.frame(Project=c(123,123,123,123,123,123,123,123,124,124,124,124,124,125,125), Value=c(1,2,3,4,7,3,8,9,8,3,2,5,6,2,3), OldValue=c("","Open","In Progress","Open","In Progress", ...

Sending data to the makeStyle function in TypeScript

How can I set the style of backgroundImage in my React component based on the value of post.mainImage? Here is the code snippet: import React from 'react'; import { Post } from '../interfaces'; import { makeStyles, createStyles, Theme ...

Interface with several generic types

In an attempt to create a parser that can parse data fields and convert them into a complete form for display purposes, the fields property plays a crucial role. This property will define each field in a JSON data array that the client receives from the ur ...