Ziv Glazer
Ziv Glazer

Reputation: 826

array with interface as type (polymorphism with interfaces)

I'm trying to create an array of objects, where all objects implement the interface Foo. Here is a simplified example to demonstrate the problem:

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[]'

Shouldn't this behavior be supported? If not, what are the alternatives to code such behavior?

Upvotes: 1

Views: 2067

Answers (2)

Nitzan Tomer
Nitzan Tomer

Reputation: 164417

You're adding the class to your array instead of the instance of that class.
Should be:

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

This will also work:

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

Edit

I'm not an angular developer so I can't relate to that, but if I understand you correctly then you need an array of classes and not instances, which in javascript means that you need an array of constructors.

That's easy to do in typescript:

interface FooConstructor {
    new (): Foo;
}

interface Foo {
    fooAction(): any;
}

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

let arrayThatINeed : FooConstructor[] = [Bar];

You'll see that this code doesn't result in errors, but it's not correct either because that it won't complain even if you remove the implements part from the Bar class.
I can find reasons for why that's the case, but I think that the compiler should complain about it none the less.

You can solve that if you make Foo a class, for example:

interface FooConstructor {
    new (): Foo;
}

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

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

let arrayThatINeed : FooConstructor[] = [Bar];

Now if you remove the extends part from Bar you'll get an error.
But you must have at least one non-abstract method/member in Foo for it to work (that is, it will complain if what's in the array isn't a class extending Foo).

Upvotes: 3

Fenton
Fenton

Reputation: 251242

If you expect the array items to satisfy the Foo[] interface, items need to satisfy an object with the properties of a Foo (i.e. the method fooAction). Until you instantiate an instance of Bar, it does not satisfy the interface.

var barInstance = new Bar();

let items: Foo[] = [ barInstance ];

If you want the array to contain Foo types, not instantiated classes, you can create a type to represent that - if you make Foo an abstract class.

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

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

type FooType = typeof Foo;

let arrayThatINeed : FooType[] = [Bar];

Upvotes: 3

Related Questions