根据模板参数访问打字稿对象属性

时间:2019-06-23 13:28:35

标签: typescript templates

我想创建一个Typescript集合类,该类按字段查找项目,如下所示:

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

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

然后我想用类似这样的实例化它:

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

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

不幸的是,这行不通,我在引用item[K]之类的错误消息中说K是类型而不是值。我了解导致错误的原因,但我不知道该如何解决。在Typescript中甚至有可能吗?

1 个答案:

答案 0 :(得分:2)

您需要在运行时的某个地方传递类型为K的值,此功能才能起作用。如果我正确理解了Collection类的要点,则将需要一个T的实际数组和一个K类型的值。获得这些值的一个好地方是在构造新的Collection实例时。也就是说,使构造函数将其作为参数:

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
    );
  }
}

然后,您可以按预期使用它(我想是这样,无论如何……您实际上并没有显示用例)。给定这些类型和对象:

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];

您可以构造一个新的Collection

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

通过类型推断,itemCollection的类型为Collection<MyItem, "idField">。并使用它:

console.log(itemCollection.isItemInCollection(itemA)); // true
console.log(itemCollection.isItemInCollection(itemC)); // false
console.log(
  itemCollection.isItemInCollection({ idField: "A", otherField: 2893 })
); // true so be careful

好的,希望能有所帮助。祝你好运!

Link to code