Retrieve the property of a Typescript object using a template argument

I am looking to develop a Typescript Collection class that can locate items by field. Here is an example of what I have in mind:

class Collection<T, K keyof T> {
    private _items: T[];

    public isItemInCollection(item: T) {
        return _items.find((a) => a[K] === item[K], this._items) !== undefined;
    }
 }

My goal is to then create an instance like this:

interface MyItem {
    idField: string,
    otherField: number,
}

class ItemCollection: MyCollection<MyItem, 'idField'> { }

Unfortunately, when attempting to implement this approach, I encounter an error regarding the reference to item[K], stating that K is a type and not a value. Although I understand the source of the issue, I am unsure of how to resolve it. Is achieving this functionality feasible in Typescript?

Answer №1

For this to function properly, you will need to provide a value of type K at runtime. If I have grasped the concept of your Collection class correctly, both an actual array of type T and a value of type K are required. The best way to obtain these values is during the construction of a new instance of Collection. Therefore, it is recommended to have the constructor accept these as parameters:

class Collection<T, K extends keyof T> {
  private _items: T[];
  private _idKey: K;
  constructor(items: T[], idKey: K) {
    this._items = items;
    this._idKey = idKey;
  }

  public isItemInCollection(item: T) {
    return (
      this._items.find(a => a[this._idKey] === item[this._idKey]) !== undefined
    );
  }
}

With this setup, you can proceed with usage as expected (assuming no details were provided about your specific use case). Taking into account the following types and objects:

interface MyItem {
  idField: string;
  otherField: number;
}
const itemA: MyItem = { idField: "A", otherField: 1 };
const itemB: MyItem = { idField: "B", otherField: 2 };
const itemC: MyItem = { idField: "C", otherField: 3 };

const items: MyItem[] = [itemA, itemB];

You can initialize a new Collection:

const itemCollection = new Collection(items, "idField");

From type inference, it can be deduced that itemCollection is of type

Collection<MyItem, "idField">
. Further interactions include:

console.log(itemCollection.isItemInCollection(itemA)); // true
console.log(itemCollection.isItemInCollection(itemC)); // false
console.log(
  itemCollection.isItemInCollection({ idField: "A", otherField: 2893 })
); // Be cautious, result is true

Hopefully, this explanation clarifies things for you. Best of luck!

Link to 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

Having trouble launching the freshly developed Angular app

I'm encountering an issue with my newly created app - I can't seem to launch it. Error: The loader “C:/C#/Angular/my-app/src/app/app.component.css” is not providing a string as expected. I've attempted reinstallation of Angular and Nod ...

What should I do when dealing with multiple submit buttons in NextJS?

How can I differentiate between two submit buttons in a form component created in Next.js? I'm struggling to determine which button was pressed and need help resolving this issue. import React from "react"; const LoginPage = () => { as ...

What could be causing these Typescript compilation errors I am experiencing?

I am puzzled by the appearance of these errors, especially since I copied the entire ClientApp folder from a running application where they did not exist. https://i.sstatic.net/tcO5S.png Here is the structure of my project: https://i.sstatic.net/P4Ntm.p ...

Whenever signing in with Next Auth, the response consistently exhibits the values of "ok" being false and "status" being 302, even

I am currently using Next Auth with credentials to handle sign-ins. Below is the React sign-in function, which can be found at this link. signIn('credentials', { redirect: false, email: email, password: password, ...

When compiling TypeScript, the exported module cannot be located

I've encountered an issue while working on my TypeScript project. Upon compiling my code with the following configuration: { "compilerOptions": { "target": "ESNext", "module": "ESNext", & ...

Leverage the power of forkJoin in JavaScript by utilizing objects or sourcesObject

I'm currently facing an issue with my code snippet below: getInformations().subscribe( informations => { let subs = []; for (const information of informations) { subs.push(getOtherDetails(information.id)); } ...

Utilizing pattern matching in switch statements

Imagine I have different APIs that provide data about various animals. Despite some shared properties, the JSON payloads for each animal type are quite unique and specific. To avoid chaos in my code, I am looking to create strongly typed TypeScript classe ...

Properly specifying the data type for a generic type variable within a function in TypeScript

As I work on my express project, I am currently coding a function called route. const morph = (params: Function[]) => (req: Request) => params.map(f => f(req)) const applyTransformers = (transformers: Function[]) => (response: any) => { ...

Stop users from switching to other tabs within mat-tab-group without using ViewChild

I am working with a mat-tab-group component in Angular : mat-tab-group class="brand-tabs" [disableRipple]="true" *ngSwitchCase="types.project" (selectedTabChange)="changeProjectTab($event)" [selectedIndex]="selectedProjectIndex" > . ...

Tips for resolving type checking errors in TypeScript and React

I encountered an error and would appreciate any assistance in resolving it. My tech stack consists of react, typescript, and Material UI. I am attempting to customize a button using the following link: https://mui.com/material-ui/customization/how-to-custo ...

Guidance on specifying a type based on an enum in Javascript

I have a list of animals in an enum that I want to use to declare specific types. For instance: enum Animals { CAT = 'cat', DOG = 'dog', } Based on this Animal enum, I wish to declare a type structure like so: type AnimalType = { ...

Node OOM Error in Webpack Dev Server due to Material UI Typescript Integration

Currently in the process of upgrading from material-ui v0.19.1 to v1.0.0-beta.20. Initially, everything seems fine as Webpack dev server compiles successfully upon boot. However, upon making the first change, Node throws an Out of Memory error with the fol ...

"Navigate with ease using Material-UI's BottomNavigationItem and link

What is the best way to implement UI navigation using a React component? I am currently working with a <BottomNavigationItem /> component that renders as a <button>. How can I modify it to navigate to a specific URL? class FooterNavigation e ...

How to Invoke a TypeScript Function in Angular 2 Using jQuery

Using the Bootstrap-select dropdown in Angular 2 forms with jQuery, I am attempting to call a Typescript method called onDropDownChangeChange on the onchange event. However, it seems to not be functioning as expected. import { Component, OnInit, ViewChi ...

Ways to ascertain if a TypeScript type is a specific value

Can a utility type be created to identify whether a type is a literal value? For example: type IsLiteral<T> ... type IsStringALiteral = IsLiteral<string> // false type IsStringLiteralALiteral = IsLiteral<'abc'> // true type IsS ...

Creating a regular expression for validating phone numbers with a designated country code

Trying to create a regular expression for a specific country code and phone number format. const regexCountryCode = new RegExp('^\\+(48)[0-9]{9}$'); console.log( regexCountryCode.test(String(+48124223232)) ); My goal is to va ...

Your search parameter is not formatted correctly

I am currently working on filtering a collection based on different fields such as name by extracting the values from the URL parameters. For example: http://localhost:3000/patient?filter=name:jack I have implemented a method to retrieve and convert these ...

Should we utilize the component @Input as a parameter for the injected service constructor, or should we opt for the ServiceFactory

Within Angular 12 lies a simplified component structured as follows: @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.less'] }) export class ListComponent implements ...

Connect the keys from one enum to either keys or values in another enum

When working with the code below, it is important that the keys of PropertiesNamesInDataBase align with those in User.Keys. While the values of PropertiesNamesInDataBase are used in the backend, it is crucial for uniformity that the names match in the fron ...

Tips on preventing repeated data fetching logic in Next.js App Routes

I'm currently developing a project with Next.js 13's latest App Routes feature and I'm trying to figure out how to prevent repeating data fetching logic in my metadata generation function and the actual page component. /[slug]/page.tsx expo ...