以接口为类型的数组(带接口的多态性)

array with interface as type (polymorphism with interfaces)

我正在尝试创建一个对象数组,其中所有对象都实现接口 Foo。这是一个演示问题的简化示例:

interface Foo {
    fooAction(): any;
}

class Bar implements Foo
{
     public fooAction() {
          return "nothing important";
      }
 }

 let arrayThatINeed : Foo[] = [Bar]; // Type error: Type Bar[] is not 
                                     // assigable to type 'Foo[]'

不应该支持这种行为吗?如果不是,有什么替代方法可以对此类行为进行编码?

您正在将 class 添加到您的数组而不是 class 的实例。
应该是:

let arrayThatINeed : Foo[] = [new Bar()];

这也有效:

let arrayThatINeed : Foo[] = [{
    fooAction: () => { console.log("yo"); }
}];

编辑

我不是 angular 开发人员,所以我无法理解这一点,但如果我对你的理解正确,那么你需要一个 class 数组而不是实例,它在 javascript 意味着你需要一个构造函数数组。

这在打字稿中很容易做到:

interface FooConstructor {
    new (): Foo;
}

interface Foo {
    fooAction(): any;
}

class Bar implements Foo {
    public fooAction() {
        return "nothing important";
    }
}

let arrayThatINeed : FooConstructor[] = [Bar];

您会看到此代码不会导致错误,但它也不正确,因为即使您从 Bar 中删除 implements 部分,它也不会报错 class.
我可以找到为什么会这样的原因,但我认为编译器应该抱怨它 none 更少。

如果将 Foo 设为 class 就可以解决这个问题,例如:

interface FooConstructor {
    new (): Foo;
}

abstract class Foo {
    abstract fooAction(): any;
    fn() {}
}

class Bar extends Foo {
    public fooAction() {
        return "nothing important";
    }
}

let arrayThatINeed : FooConstructor[] = [Bar];

现在,如果您从 Bar 中删除 extends 部分,则会出现错误。
但是你必须在 Foo 中至少有一个非抽象的 method/member 才能工作(也就是说,如果数组中的内容不是 class 扩展 Foo).

如果您希望数组项满足 Foo[] 接口,则项需要满足具有 Foo 属性的对象(即方法 fooAction)。直到你实例化一个Bar的实例,它才不满足接口

var barInstance = new Bar();

let items: Foo[] = [ barInstance ];

如果您希望数组包含 Foo 类型,而不是实例化的 classes,您可以创建一个类型来表示它 - 如果您将 Foo 设为抽象 class.

abstract class Foo {
    abstract fooAction(): any;
}

class Bar extends Foo {
     public fooAction() {
          return "nothing important";
      }
 }

type FooType = typeof Foo;

let arrayThatINeed : FooType[] = [Bar];