1

In Java with Spring, if I wanted an instance to know the thing that could handle it I would write something like this

interface Executable<T extends Executor> {
   Class<T> executorClass();
}

Executable instance = () -> MyExecutor.class;
Class<T> execClazz = instance.executorClass();
T executor = context.getBean( execClazz );
Results r = executor.execute( instance );

Can I use this pattern with Aurelia and Typescript? if so how do I define the return type on executorClass in Typescript (I don't know what they use for Class or how to simply return it). How would I get the type from Aurelia's Container?

xenoterracide
  • 16,274
  • 24
  • 118
  • 243

1 Answers1

6

You can request an instance of a type from the container using the get method:

class Foo {
}

let foo = container.get(Foo); // returns an instance of Foo.

In TypeScript, you'd probably want to cast the result of the get method:

class Foo {
}

let foo = <Foo>container.get(Foo); // returns an instance of Foo.

If you have multiple types that implement a particular interface, register the appropriate implementation at app startup:

// interface
class FooService {
  getFoos(): Promise<Foo[]> {
    throw new Error('not implemented'); 
  }
}

class HttpFooService {
  getFoos(): Promise<Foo[]> {
    return fetch('https://api.evilcorp.com/foos')
      .then(response => response.json());
  }
}

class MockFooService {
  getFoos(): Promise<Foo[]> {
    return Promise.resolve([new Foo()]);
  }
}

// app startup... configure the container...
if (TEST) {
  container.registerHandler(FooService, c => c.get(MockFooService));
  // or: container.registerInstance(FooService, new MockFooService());
} else {
  container.registerHandler(FooService, c => c.get(HttpFooService));
  // or: container.registerInstance(FooService, new HttpFooService());
}

// now when you @inject(Foo) or container.get(Foo) you'll get an instance of MockFooService or HttpFooService, depending on what you registered.
let foo = container.get(Foo); // returns an instance of MockFooService/HttpFooService.

I'm not sure if this answers your question entirely. I've never used Spring and haven't done any Java programming in a while. I didn't quite follow the code in your question. Here's a link to several container/DI use cases that might be helpful. Here's another stackoverflow answer that might be helpful. Here are the Aurelia DI docs.

As a side note, stay away from container.get when possible. Using it violates the dependency inversion principle. Better to list your dependencies than to actively retrieve them:

Good (ES6):

@inject(Foo, Bar)
class Baz {
  constructor(foo, bar) {
  }
}

Good (TypeScript):

@autoinject
class Baz {
  constructor(foo: Foo, bar: Bar) {
  }
}

Not so good:

class Baz {
  constructor() {
    let foo = container.get(Foo);
    let bar = container.get(Bar);
  }
}
Community
  • 1
  • 1
Jeremy Danyow
  • 26,470
  • 12
  • 87
  • 133
  • the reason for using .get( Type ) instead of injecting by type is you don't actually know what type you want ahead of time usually this is because you're dependent on an interface, that has multiple injectable implementations but you only want one of them and a parameter of yours can tell you which one. See you wouldn't write `container.get(Foo)` that'd be bad you'd write `constructor( param ) { this.type = container.get( param.type() ) }`. Anyways you're only missing one part. I'm not sure how to return the type from the parameter, can't seem to find a Class object/type in Typescript. – xenoterracide Aug 02 '16 at 02:47
  • I suppose I could simply do `type() { return Foo }` but that really doesn't give a great interface method signature. – xenoterracide Aug 02 '16 at 03:00