1

Is it possible in angular 2 to consume many classes as array, given they all implement an interface? For example:

interface IWorker {
   doWork();
}

class WorkerA implements IWorker {
   doWork() {...}
}

class WorkerB implements IWorker {
   doWork() {...}
}

class MainWorker {
    constructor(private workers: IWorker[]) {
    }

    doWork() {
        this.workers.forEach(w => w.doWork());
    }
}
Amiram Korach
  • 13,056
  • 3
  • 28
  • 30
  • In Typescript, `private worker: WorkerA ` expects a Class not Interface and it usually creates an instance of the class with the same type and stores it in the `worker` object. It's not just typecasting FTR. So answer is no! – codef0rmer Jan 22 '17 at 10:08
  • Could you be more precise about what you're trying to ask? That's not correct syntax for an array of something (`something[]`, not `[something]`) and you're missing a `this.`, but you can certainly have an interface-typed array, put instances of implementing classes in it, iterate over them and interact with them using that interface. Do you have code that doesn't work (provide a [mcve])? Are you asking about dependency injection of the array? – jonrsharpe Jan 22 '17 at 10:13
  • @jonrsharpe fixed the code. What I'm trying to achieve is to inject all classes implement an interface into a single array. I don't want the worker class to import all kind of workers. I want to be able to just add a worker and make it injected into the workers array without changing the main worker, – Amiram Korach Jan 22 '17 at 11:32
  • If you want to use it with DI, look up `OpaqueToken`. – jonrsharpe Jan 22 '17 at 11:33
  • @jonrsharpe sorry but I don't understand how `OpaqueToken` is related to this. – Amiram Korach Jan 22 '17 at 11:34
  • @jonrsharpe should be similar to this in MEF http://dotnetbyexample.blogspot.co.il/2010/04/very-basic-mef-sample-using-importmany.html – Amiram Korach Jan 22 '17 at 11:37
  • Because the token is what tells the DI system what you mean when you ask for something; you can assign your array of classes to it then inject it. If you mean you want the array to be created purely by virtue of the classes implementing the interface (in which case please edit to clarify) then I don't know how. – jonrsharpe Jan 22 '17 at 11:49

1 Answers1

0

You can make IWorker an abstract base class instead of an interface. Interfaces are not supported by Angulars DI, because interface information is not available at runtime.

Alternatively you can use a string or OpaqueToken as key instead of the interface.

string key example:

@Injectable() // <<<=== required if DI should inject parameters
class MainWorker {
    constructor(@Inject('IWorker') private workers: IWorker[]) {}

    doWork() {
        this.workers.forEach(w => w.doWork());
    }
}

To get WorkerA and WorkerB passed to MainWorker as array, they need to be registered with useMulti: true

providers: [
  {provide: 'IWorker', useClass: WorkerA, useMulti: true},
  {provide: 'IWorker', useClass: WorkerB, useMulti: true},
]

See also What is in Angular 2 Opaque Token and What's the Point?

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567