Attempting to utilize Array Methods with an Array Union Type

Currently, I am in the process of refactoring an Angular application to enable strict typing.

One issue I have encountered is using array methods with an array union type in our LookupService. When attempting to call

const lookup = lookupConfig.find(l => l.code === code);
, an error pops up:

This expression is not callable. Each member of the union type '{ <S extends Lookup>(predicate: (this: void, value: Lookup, index: number, obj: Lookup[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: Lookup<...>, index: number, obj: Lookup<...>[]) => unknown, thisArg?: any): Lookup<...> | undefined; } | { ...; } | { ...; }' has signatures, but none of those signatures are compatible with each other.

I've experimented with various solutions from Github and StackOverflow but haven't found a way to achieve this without creating new methods for each current and future union types as mentioned in this answer.

I've created a TS Playground which can be viewed below:

interface Lookup<T extends number | string = number> {
    code: T;
    name: string;
}

interface ProvinceLookup extends Lookup<string> {
  countryCode: string;
}

interface LookupConfig {
  college: Lookup[];
  countries: Lookup<string>[];
  provinces: ProvinceLookup[];
}

const lookupConfig: Lookup<number>[] | Lookup<string>[] | ProvinceLookup[] = [];

function getLookup<T extends number | string>(code: T) {
  return lookupConfig.find((l: Lookup<T>) => l.code === code);
};

const result = getLookup(1);

The actual implementation where find generates the error:

private lookupValue<T extends string | number>(
  lookupCode: T,
  lookupKey: string,
  key: string
): unknown | null {
  const lookupConfig = this.lookupService[lookupKey as keyof LookupConfig];
  const lookup = lookupConfig?.find((l: Lookup) => l.code === lookupCode);

  return lookup && Object.prototype.hasOwnProperty.call(lookup, key)
    ? lookup[key]
    : null;
}

Answer №1

I took advantage of the fact that each lookup inherits from Lookup in order to continue working based on @arno-van-liere's feedback. Despite the existence of keys on different lookups that are not present in Lookup (such as countryCode on provinces), using hasOwnProperty for property checking ensures safety even though the property access typing may be inaccurate.

If anyone knows of a more type-safe solution, I am open to making changes. For now, I have noted above the return code that it may not be entirely accurate:

private lookupValue<T extends number | string>(
  lookupCode: T,
  lookupKey: string,
  key: string
): unknown | null {
  const lookupConfig = this.lookupService[lookupKey as keyof LookupConfig];
  const lookup = (lookupConfig as Lookup<T>[])?.find(
    (l: Lookup<T>) => l.code === lookupCode
  );

  return lookup && Object.prototype.hasOwnProperty.call(lookup, key)
    ? lookup[key as keyof Lookup<T>]
    : null;
}

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

When trying to access a string value for an ID, I encountered an error stating "Element implicitly has an 'any' type because index expression is not of type 'number'.ts(7015)"

Currently, I am working on a project using React and Typescript. My goal is to retrieve a specific string with the key name id from an array of ten objects that contain the id. The screenshot displaying the code produces the desired output in the console; ...

The real file that was brought in after indicating a module in the node_modules directory that was coded in Typescript

After creating a typescript module named moduleA, I am ready to publish this package and make it accessible from another typescript project. Currently, for testing purposes, I have installed 'moduleA' using 'npm install ../moduleA'. Th ...

The build error TS1036 is thrown when a function with a return statement is moved to index.d.ts, even though it worked perfectly in a standard TS file

In my project using Node v14.x and StencilJS (React) v2.3.x, I encountered an issue with a test-helper file containing a function that converts string-arrays to number-arrays: export function parseNumericStringOrStringArrayToIntegers(value: string | (strin ...

Is it possible to determine the specific type of props being passed from a parent element in TypeScript?

Currently, I am working on a mobile app using TypeScript along with React Native. In order to maintain the scroll position of the previous screen, I have created a variable and used useRef() to manage the scroll functionality. I am facing an issue regardi ...

What is the best way to include the parameter set in the interceptor when making a post request?

-> Initially, I attempt to handle this scenario in the axios request interceptor; if the parameter is uber, then utilize a token. If the parameter is not uber, then do not use a token. -> Afterward, how can I specify uber as a parameter in the custo ...

Tips for preventing the overwriting of a JSON object in a React application

I'm trying to compare two JSON objects and identify the differing values in the second JSON object based on a specific key. My goal is to store these mismatched values in a new JSON object. The current issue I'm facing is that when there are mult ...

Oops! An issue occurred: [RunScriptError]: Running "C:Windowssystem32cmd.exe /d /s /c electron-builder install-app-deps" resulted in an error with exit code 1

query: https://github.com/electron/electron/issues/29273 I am having trouble with the installation package as it keeps failing and showing errors. Any tips or suggestions would be highly appreciated. Thank you! ...

Utilizing React to pass parent state to a child component becomes more complex when the parent state is derived from external classes and is subsequently modified. In this scenario,

I'm struggling to find the right way to articulate my issue in the title because it's quite specific to my current situation. Basically, I have two external classes structured like this: class Config { public level: number = 1; //this is a s ...

Is there a way to retrieve the request URL within the validate function of the http strategy?

Is it possible to access the context object present in guards within the validate method of my bearer strategy, by passing it as an argument along with the token? bearer-auth.guard.ts: @Injectable() export class BearerAuthGuard extends AuthGuard('be ...

What could be causing my TypeScript project to only fail in VScode?

After taking a several-week break from my TypeScript-based open-source project, I have returned to fix a bug. However, when running the project in VScode, it suddenly fails and presents legitimate errors that need fixing. What's puzzling is why these ...

Step by step guide on integrating current locations in Leaflet OpenStreetMap within an Angular application

I am currently working on an Angular application that incorporates a map using Leaflet OpenStreetMap. I want to display the real-time latitude and longitude for the map, which should update based on the location. Can someone advise me on how to add the cur ...

Prevent clicking outside the bootstrap modal in Angular 4 from closing the modal

Just starting out with angular4 and incorporating bootstrap modal into my project. I want the modal to close when clicking outside of it. Here's the code snippet: //in html <div bsModal #noticeModal="bs-modal" class="modal fade" tabindex="-1" rol ...

Tips on implementing zod schema types with remapped fields using the toZod method

I'm currently working on mapping a schema key to a different name in my database interface Country { isoCode: string, nameEn: string, nameDe: string, phone: string, bla: string } const CountryJson = { i ...

Mastering the art of utilizing GSI Index and FilterExpression in AWS DynamoDB querying

In my DynamoDB database table, I have the following structure. It consists of a primary key (ID) and a sort key (receivedTime). ID(primary key) receivedTime(sort key) Data ID1 1670739188 3 ID2 167072 ...

Developing Angular applications with numerous projects and libraries in the build process

The other day I successfully deployed the initial version of our front-end application, but encountered some confusion during the build process setup. Many Angular apps do not utilize the workspace feature unless they are creating multiple standalone appli ...

Converting UK DateTime to GMT time using Angular

I am currently working on an angular project that involves displaying the start and end times of office hours in a table. For instance, the office operates from 8:30 AM to 5:30 PM. This particular office has branches located in the UK and India. Since u ...

Issues arising post transitioning to 14.0.0 from 13.0.0 version of ngx-masonry library leading to failed tests

Following the update to the latest stable version of the library ngx-masonry 14.0.0, our tests started failing. The release was just yesterday (24.10.2022) and you can find the changelog here: https://github.com/wynfred/ngx-masonry/blob/master/CHANGELOG.md ...

The new update of ag-grid, version 18.1, no longer includes the feature for enabling cell text selection

I am attempting to disable the clipboard service in ag-grid. I have come across the enableCellTextSelection flag, which supposedly disables it completely. However, when I try to use this flag as a direct property of <ag-grid-angular>, it results in a ...

Is it possible that Angular 6's ngOnChanges directive is not compatible with a lambda expression?

Currently, I am in the process of creating an attribute directive that is designed to alter the background color of the host element based on a provided "quality" @input. While experimenting with my directive, I discovered that using ngOnChanges as a lamb ...

Retrieve parent route parameters from a dynamically loaded route component

Struggling to access the parent route params in a lazy loaded route component using activatedRoute.parent.params. Despite this not working, I have managed to find a solution that involves fetching the value using an array index number which feels like a &a ...