【问题标题】:Arrays and generic classes that extends another class: Possible in typescript?扩展另一个类的数组和泛型类:在打字稿中可能吗?
【发布时间】:2016-11-11 18:00:42
【问题描述】:

我有一个通讯录和两种类型的联系人:

  • 人员
  • 组织

它们都扩展了 Contact 类。


我想要一个类的方法返回一个联系人数组

public method(args...): Array<Contact> {...}

很好,但是如果我有那个方法来对数组内的联系人的某些属性做一些事情呢?

public method(args...): Array<Contact> {
  contacts :Array<Contact> = getContactsFromSomewhere();
  contacts.forEach( contact => {
    if(typeof contact === "Person"){ //persons and organizations are different, they have different atrributes
      //Here i modify some Person attributes
    }
    else{
      //Here i modify some Organization attributes
  });
  return contacts;

这感觉很麻烦,难以阅读。 为什么不这样呢?

public method(args...): Array<T extends Contact> {
  contacts :Array<T extends Contact> = getContactsFromSomewhere();
  contacts.forEach( contact => {
    contact.doSomething() //abstract method implemented in both classes its own way.
  });
  return contacts;

不可能,我做不到

Array<T extends Contact>

这个错误是 VSCode 抛出的:

[ts] 泛型“数组”需要 1 个类型参数

是否可以使用使用泛型类的数组来扩展打字稿中的另一个类?

【问题讨论】:

    标签: typescript angular


    【解决方案1】:

    正如您所写,您似乎根据您的问题知道问题的答案:

    contact.doSomething() //两个类都实现的抽象方法 走自己的路

    您可以使用您已有的相同方式,而无需“繁琐”的部分。

    例如,如果您想过滤掉以字符串开头的联系人,那么只需为Contact 提供一个startsWith 方法并在所有子类中实现它,那么当您迭代联系人时,此方法始终可用并且具体类型无需查看:

    public startsWith(prefix: string): Array<Contact> {
        return getContactsFromSomewhere().filter(contact => contact.startsWith(prefix));
    }
    

    由于您可能在基类 Contact 中拥有联系人姓名,因此无需将其抽象化,只是为了示例。

    如果您需要区别对待联系人,您有 3 个选项:

    (1) 像你一样检查类型:

    public sizeGreaterThan(min: number): Array<Contact> {
        return getContactsFromSomewhere().filter(contact => {
            if (contact instanceof Person) {
                return min === 1;
            } else {
                return (contact as Organization).size() >= min;
            }
        });
    }
    

    (2) 有不同的联系人“getter”过滤联系人数组:

    function getOrganizations(contacts: Contact[]) {
        return contacs.filter(contact => contact instanceof Organization);
    }
    
    public sizeGreaterThan(min: number): Array<Contact> {
        return getOrganizations(getContactsFromSomewhere()).filter(organization => organization.size() >= min);
    }
    

    (3)对不同的类型有不同的数据结构,然后同(2)中的操作。

    您的代码中还有两个 cmets:

    • 在你的方法中使用 varlet 作为 contacts 变量,否则你会污染全局命名空间

    • 使用instanceof 而不是typeof,因为:

    (code in playground)

    class A {}
    
    let a = new A();
    console.log(typeof a); // "object"
    console.log(a instanceof A); // true
    

    【讨论】:

      【解决方案2】:

      您不能声明这样的通用签名,在您的示例打字稿中认为您要使用 Array 的通用签名,而 T extends Contact 不是类型,它是一个通用签名。

      你可以这样做:

      public method<T extends Contact>(...args): Array<T>
      {
          var contacts: Array<T> = getContactsFromSomewhere();
          contacts.forEach( contact => {
              contact.doSomething() //abstract method implemented in both classes its own way.
          });
          return contacts;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-10-04
        • 1970-01-01
        • 1970-01-01
        • 2020-08-18
        • 1970-01-01
        • 2017-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多