首页 > 解决方案 > 将对象和密钥传递给 Angular 中的通用组件:T[K]

问题描述

我正在使用 Angular 和 Typescript 4.4.4 版。我正在尝试创建一个通用组件,在其中设置 obj(数据对象)和 key(属性)。

我的文本组件如下(简化):


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

  @Input()
  obj : T;

  @Input()
  key: K;

  constructor(){}

  // challenge: we cannot change the signature of this function, simulation purpose 
  currency(cost: string | number) {
    console.log('func::currency', cost);
  }

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

// text.component.html (template)
// currency is an PipeTranform build-in Angular
//{{ obj[key] | currency:'US' }}

不幸的是,我被这个错误困住了,我不知道要克服这个问题。

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'.

当然,我可以使用this.currency(this.obj[this.key] as any);,但我不想那样做。

打字稿游乐场

标签: angulartypescript

解决方案


这个怎么样...

interface VideoAssets extends Record<string, string|number> {
  id: string;
  runtime: string;
  date: string;
  cost: number;
}

const videoAsset: VideoAssets = {
  id: "1",
  runtime: "02:02:02",
  date: "2021-11-05",
  cost: 11.99,
}

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

  obj : T;
  key: K;

  constructor(obj: T, key: K){
    this.obj = obj;
    this.key = key;
  }

  // challenge: we cannot change the signature of this function
  currency(cost: string | number) {
    console.log('func::currency', cost);
  }

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

  print(){
    console.log('func::print', this.obj[this.key]);
  }
}

// text.component.html
// currency is PipeTranform from build-in Angular
//{{ {{ obj[key] | currency:'US' }} }}


// test
const component = new TextComponent(videoAsset, 'cost');
component.test();
component.print();

游乐场演示


推荐阅读