Sending a specific object and its corresponding key as parameters to a reusable component in Angular: T[K]

I am currently working on developing a generic component in Angular and Typescript version 4.4.4. The goal is to create a component where I can set both an object (obj) and specific keys (properties).

Here's a simplified version of my text component:


// text.component.ts
class TextComponent<T, K extends Extract<keyof T, string>> {

  @Input()
  obj : T;

  @Input()
  key: K;

  constructor(){}

  // The challenge lies in not being able to change the function signature for simulation purposes 
  currency(cost: string | number) {
    console.log('func::currency', cost);
  }

  test(){
      this.currency(this.obj[this.key]);
  }
}

// text.component.html (template)
// Currency is a built-in PipeTransform feature in Angular
//{{ obj[key] | currency:'US' }}

Unfortunately, I have encountered an error that I'm struggling to resolve.

Argument of type 'T[K]' is not assignable to parameter of type 'string | number'.
  Type 'T[Extract<keyof T, string>]' is not assignable to type 'string | number'.
    Type 'T[string]' is not assignable to type 'string | number'.
      Type 'T[string]' is not assignable to type 'number'.
        Type 'T[Extract<keyof T, string>]' is not assignable to type 'number'.
          Type 'T[K]' is not assignable to type 'number'.
            Type 'T[Extract<keyof T, string>]' is not assignable to type 'number'.
              Type 'T[string]' is not assignable to type 'number'.

Although using

this.currency(this.obj[this.key] as any);
might be a temporary solution, I would prefer not to go down that route.

TypeScript Playground

Answer №1

How about this approach...

interface MediaFiles extends Record<string, string|number> {
  id: string;
  duration: string;
  releaseDate: string;
  price: number;
}

const mediaFile: MediaFiles = {
  id: "1",
  duration: "02:02:02",
  releaseDate: "2021-11-05",
  price: 11.99,
}

class CustomComponent<T extends Record<string, string|number>, K extends Extract<keyof T, string>> {

  data : T;
  selectedKey: K;

  constructor(data: T, selectedKey: K){
    this.data = data;
    this.selectedKey = selectedKey;
  }

  // challenge: we must keep the signature of this function unchanged
  currency(amount: string | number) {
    console.log('method::currency', amount);
  }

  validate(){
      this.currency(this.data[this.selectedKey]);
  }

  display(){
    console.log('method::display', this.data[this.selectedKey]);
  }
}

// file.component.html
// currency is a custom PipeTranform in Angular framework
//{{ {{ data[selectedKey] | currency:'USD' }} }}

// testing phase
const componentInstance = new CustomComponent(mediaFile, 'price');
componentInstance.validate();
componentInstance.display();

Interactive Demo Link

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

A comprehensive guide to dynamically rendering components and implementing dynamic CSS in Angular 6

I successfully implemented a Directive, but I am now facing the challenge of adding CSS styling to it. I have experimented with array objects, however, I ended up applying CSS directly in the HTML. My goal is to create a single component where I can pass ...

Difficulties setting up TypeScript in Laravel, alongside Vuejs and Inertia

Currently, my tech stack includes Laravel, Vue, and Inertia. However, I am looking to migrate everything to TypeScript, and I have encountered a roadblock that I can't seem to overcome. To aid me in this process, I referred to the following video tuto ...

Having trouble getting useFieldArray to work with Material UI Select component

I am currently working on implementing a dynamic Select field using Material UI and react-hook-form. While the useFieldArray works perfectly with TextField, I am facing issues when trying to use it with Select. What is not functioning properly: The defau ...

An Array of objects is considered NULL if it does not contain any values before being iterated through

Working with Files in TypeScript (Angular 8) has led me to Encode the files in Base64 using the code below: private async convertToBase64(evidences: Array<EvidenceToDisplay>): Promise<Array<EvidenceToDownload>> { const results: Arr ...

What could be causing the error in the console when I try to declare datetime in Ionic?

I am just starting out with Ionic and Angular, but I seem to have hit a roadblock. The compiler is throwing an error that says: node_modules_ionic_core_dist_esm_ion-app_8_entry_js.js:2 TypeError: Cannot destructure property 'month' of '(0 , ...

Simple and quickest method for incorporating jQuery into Angular 2/4

Effective ways to combine jQuery and Angular? Simple steps for integrating jQuery in Angular2 TypeScript apps? Not sure if this approach is secure, but it can definitely be beneficial. Quite intriguing. ...

Divide a string using multiple delimiters just one time

Having trouble splitting a string with various delimiters just once? It can be tricky! For instance: test/date-2020-02-10Xinfo My goal is to create an array like this: [test,Date,2020-02-10,info] I've experimented with different approaches, such ...

Displaying text on a ribbon in Excel using Office JavaScript

Currently, I am working on an excel-addin project utilizing Angular and the Office JS API. My goal is to showcase a text message in an angular toast, while also displaying regular text on the right side of the ribbon/menu bar in Excel. My desired function ...

What is the best way to delete markers from a leaflet map?

I need to remove markers from my map. I am looking to create a function that will specifically clear a marker based on its ID. I am utilizing Leaflet for the map implementation. Here is my function: public clearMarkers(): void { for (var id in this. ...

What is the best method to create a TypeScript dictionary from an object using a keyboard?

One approach I frequently use involves treating objects as dictionaries. For example: type Foo = { a: string } type MyDictionary = { [key: string]: Foo } function foo(dict: MyDictionary) { // Requirement 1: The values should be of type Foo[] const va ...

Angular ngFor Directive Failing to Display Menu Item Information on Right-Click Context Menu

Currently encountering an issue with implementing a right-click function in my context menu. The menu items are not appearing due to the second ngFor="let row" condition... however, I require the selected row object from a right click to pass in a JSON val ...

Angular `CORS` Ailment

I am currently utilizing the MEAN stack (MongoDB, Express, Angular, and NodeJS). I have a basic function for fetching data from an external API as shown below: let api = 'https://thongtindoanhnghiep.co/api/city'; return this.http.get<any>(a ...

How come Typescript claims that X could potentially be undefined within useMemo, even though it has already been defined and cannot be undefined at this stage

I am facing an issue with the following code snippet: const productsWithAddonPrice = useMemo(() => { const addonsPrice = addonsSelected .map(id => { if (addons === undefined) { return 0} return addons.find(addon => addo ...

Avoid redundant GET requests in your Angular application initialization by utilizing RxJS

Is there a way to consolidate multiple http requests into one in Angular or RxJS, if they are triggered closely together? For instance, when I open my application, all 20 components call the same http request in their ngOnInit method: I have implemented ...

Utilizing TypeScript in an AngularJS (1.x) project alongside Webpack: A Step-By-Step Guide

Currently, I am working through the official guide on transitioning from AngularJS (1.x) to Angular (2+). I have successfully divided my application into Components and integrated ES6 with Webpack as the module loader. However, I now find myself unsure of ...

Improving JavaScript Functions: Minimize duplication of helper methods

I have a set of helper functions that check for the presence of specific strings in an array and certain steps before triggering other functions. The reason for keeping them separated is because arrTours must be associated with only those arrSteps. // Help ...

Angular's import and export functions are essential features that allow modules

Currently, I am working on a complex Angular project that consists of multiple components. One specific scenario involves an exported `const` object in a .ts file which is then imported into two separate components. export const topology = { "topolo ...

Angular6 HttpClient: Unable to Inject Headers in Get Request for Chrome and IE11

Under my Angular 6 application, I am attempting to make a GET request while injecting some custom Headers: Here is how my service is structured: @Injectable() export class MyService { constructor(public httpClient: HttpClient) { } getUserInfos(login): Ob ...

"Learn the process of uploading, saving, and displaying images using the powerful combination of Mongoose, Express, Angular 4,

For my app, I am utilizing Mongoose, Express, Aurelia, and NodeJS, but I consider myself a beginner in this field. One of the components I'm working on involves implementing CRUD operations that require uploading an image file. Once saved to Mongoose ...

Exploring the concept of data model inheritance in Angular 2

In my Angular2 and ASP.NET Core project, I have set up the following: My C# .NET Core API returns the following classes: public class fighter { public int id { get; set; } public string name { get; set; } public datetime birthdate { get; set; } p ...