Tips for iterating over an array that implements either of two interfaces in TypeScript

The objective is to develop a reusable method for filtering out items from an array that implements one of two interfaces

Providing a code example would be most helpful:

interface IDuration {
  start: number;
  end: number;
}

interface IRelativeDuration {
  relativeStart: number;
  relativeEnd: number;
}

export const enforceBoundries = (
  point: number,
  items: Array<IDuration> | Array<IRelativeDuration>,
): void => {

  let startKey: string
  let endKey: string

  // **HAVING TROUBLE WITH THIS**
  if(/* iDuration */) {
    startKey = 'start'
    endKey = 'end'
  } else {
    startKey = 'relativeStart'
    endKey = 'relativeEnd'
  }

  items.forEach(item => {
    if(item[startKey] > point) {
      //....
    }
  })
}

The solution might lie in Generic Constraints, but TypeScript is not my strong suit

I have tried various conditions in the if statement but can't find one that successfully compiles the application

Answer №1

One useful approach is to utilize the typeof operator to determine the type of an item before casting it to its specific type.

Answer №2

From my understanding, there is currently no direct way to validate whether a JSON object aligns with an interface during runtime in JavaScript.

The absence of interfaces in JavaScript complicates this task further, as 'typeof' would always return 'object'.

One potential workaround involves using Object.keys() to verify if all the necessary properties are included in the object:

interface IDuration {
    start: number;
    end: number;
}

interface IRelativeDuration {
    relativeStart: number;
    relativeEnd: number;
}

export const enforceBoundries = (
    point: number,
    items: Array<IDuration> | Array<IRelativeDuration>,
): void => {
    items.forEach((item: IDuration | IRelativeDuration) => {
        const props = Object.keys(item); // retrieve all keys from the item object
        let startValue = null;

        // determine if the item conforms to either of the two interfaces
        if (props.includes("start") && props.includes("end")) {
            // it fits the IDuration interface
            startValue = (item as IDuration).start;
        } else if (props.includes("relativeStart") && props.includes("relativeEnd")) {
            // it matches the IRelativeDuration interface
            startValue = (item as IRelativeDuration).relativeStart;
        } else {
            // does not correspond to IDuration or IRelativeDuration
            throw new Error("Something went wrong...");
        }

        if (startValue === null) {
            throw new Error("startValue should never be null at this point...");
        }

        if (startValue > point) {
            //....
        }
    });
}

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 characters have been found in literals within the transpiled JavaScript output

In my TypeScript code, I have a field definition that is structured like this: languages: Array<{}> = [{ key: "fr", name: "français" }]; However, when the TypeScript file is compiled into JavaScript, the output ends up looking like this: this.lan ...

Uploading CSV files in Angular 4

I am currently working on an Angular4 project where I have implemented a feature that converts data into a CSV file with a header. Now, I am looking to reverse this process and allow users to upload a CSV file instead. To test this functionality, I create ...

Having trouble appending a new attribute to the Mongoose output

In my Nodejs server application, I am working with a userDetail document that contains all the relevant user information. Additionally, I have a login document that stores the time of the first login, which I need to incorporate into the userDetails result ...

Error: Attempting to access 'config' property of undefined variable

I am currently utilizing Vue 3 with Typescript and primevue. After integrating primevue into my application, I encountered the following errors and warnings. The issue arises when I attempt to utilize the primevue 'Menubar' component, however, wh ...

Tips for efficiently awaiting outcomes from numerous asynchronous procedures enclosed within a for loop?

I am currently working on a search algorithm that goes through 3 different databases and displays the results. The basic structure of the code is as follows: for(type in ["player", "team", "event"]){ this.searchService.getSearchResult(type).toPromise ...

Encountering a 405 error when making an OpenAI API call with next.js, typescript, and tailwind CSS

I encountered a 405 error indicating that the method request is not allowed. I am attempting to trigger an API route call upon clicking a button, which then connects to the OpenAI API. Unsure of my mistake here, any guidance would be highly appreciated. E ...

Utilizing a d.ts Typescript Definition file for enhanced javascript intellisene within projects not using Typescript

I am currently working on a TypeScript project where I have set "declaration": true in tsconfig.json to generate a d.ts file. The generated d.ts file looks like this: /// <reference types="jquery" /> declare class KatApp implements IKatApp ...

How to extract a string value from an observable array in Angular2 NativeScript?

I inserted JSON data into an observable array. My goal is to extract only the address from ShowData, specifically as a string value based on its position. ShowData.ts: class ShowData{ constructor(public id:number, public name:string, public address:s ...

In TypeScript version 2.4.1, the fontWeight property encounters an error where a value of type 'number' cannot be assigned to the types of '"inherit", 400'

When attempting to set the fontWeight property in TypeScript, I encounter the following error: Types of property 'test' are incompatible. Type '{ fontWeight: number; }' is not assignable to type 'Partial<CSSProperties>&a ...

Enhancing Angular Material forms with custom background colors

I'm new to Angular and Angular material, still learning the ropes. I have been trying to create a form and needed to change the background color to Red. However, when I attempted to do so, the red color ended up covering the entire form instead of ju ...

Switch app engines in real-time based on the URL path with express framework

How can I dynamically set App Engine based on the URL? In my application, I have two render engines available: serverSideRenderEngine & browserRenderEngine If the URL is /home, the app.engine should be set as serverSideRenderEngine If the URL is /l ...

Creating Dynamic Forms in React with Typescript: A Step-by-Step Guide to Adding Form Elements with an onClick Event Handler

I am looking to create a dynamic generation of TextFields and then store their values in an array within the state. Here are my imports: import TextField from '@material-ui/core/TextField'; import Button from '@material-ui/core/Button&apos ...

It is not necessary to specify a generic type on a Typescript class

When working with Typescript and default compiler options, there are strict rules in place regarding null values and uninitialized class attributes in constructors. However, with generics, it is possible to define a generic type for a class and create a ne ...

I am encountering an issue regarding the 'endpoint' property within my environment.ts file while working on an Angular 17 project

My goal is to incorporate the property endpoint from my environment.ts file into my service: export const environment = { production: false, endpoint: 'http://localhost:3000/api/cabin/' }; This snippet showcases my service: import {Injectabl ...

Is the detection change triggered when default TS/JS Data types methods are called within an HTML template?

I'm currently updating an application where developers originally included function calls directly in the HTML templating, like this: <span>{{'getX()'}}</span> This resulted in the getX method being called after each change dete ...

SvgIcon is not a recognized element within the JSX syntax

Encountering a frustrating TypeScript error in an Electron React App, using MUI and MUI Icons. Although it's not halting the build process, I'm determined to resolve it as it's causing issues with defining props for icons. In a previous pro ...

Fetching User Details Including Cart Content Upon User Login

After successfully creating my e-commerce application, I have managed to implement API registration and login functionalities which are working perfectly in terms of requesting and receiving responses. Additionally, I have integrated APIs for various produ ...

TypeScript Compile Error: The property is not available in the 'IStateParamsService' type

My client project heavily utilizes TypeScript. Currently, I am encountering a technical issue. Within my HTML code, I have an anchor tag as shown below: <a class="btn btn-default mrm" ui-sref="course-detail({courseId: '{{c.Id}}'})">Detail ...

Determine the type of embedded function by analyzing the callback

Are you struggling to create a function that takes an object and returns a nested function, which in turn accepts a callback and should return the same type of function? It seems like achieving this with the same type as the callback is posing quite a chal ...

Utilize an array of JSON objects to populate an array of interfaces in Angular/Typescript

I am currently facing a dilemma - my code is functioning without any errors when executed, but my text editor is flagging an issue stating that the property 'categories' does not exist on type 'CategoryInterface[]' (specifically on the ...