[Au2 beta15] TypeScript constructor auto-injection no longer supported?

tl;dr beta15 doesnt inject parameters by their TS type annotation, the @inject has to be provided explicitly. Was that the plan?

The entire time I’ve been using Au2, I assumed the constructor parameter are being resolved by default based on the type annotation. I am not entirely sure I ever seen it in the docs, but looking at some old examples I found now ( see below ) I believe the scenario was correct. So, basically, I relied entirely on the TS type information, no @inject attribute or any kind of inject static properties:

In exact, the code below just worked fine.

export class MyService {
  readonly msg = 'abc';
}

export class MyApp {
  constructor (service: MyService){
    console.log(service.msg); // 'abc'
  }
}

When upgrading to beta.15 it seems no longer to be valid. Undefined is being passed for all the arguments, unless I specify the @inject attribute or static property. Which feels redundant, frankly - not to mention the amount of work to do so.

What is the valid approach on this? Is the current behavior (that is, no injection unless specified explicitly) valid, or is it a result of a bug? I’ve seen the release notes on the beta15 breaking changes, I might not understand them correctly but I don’t seem to find anything related to this scenario.

the examples:

I’m struggling to find any real-world apps or complex examples using Au2, to verify others’ approach to the DI.

The only one I found so far, is the NetPad. They seem to be injecting just like I did, that is, no @inject annotation for solid class dependencies.

CC @tareqimbasher

I think the info you’re looking for is all in the Beta 15 release, more migration info was added in there because I also found it very confusing to migrate to the new decorator. You need to use resolve instead of the previous decorators. Beta 15 had a very large breaking change related to the Decorator, in short they no longer exists

@ghiscoding thank you, however you’re referring to the decorator-based resolution that has changed and is widely covered in the Beta 15 release notes.
That is, the code that was constructor (@IEventAggregator aggr) now has to be constructor (aggr = resolve(@IEventAggregator))

My case is related to the injection of solid classes, that required no annotation at all prior to Beta 15. If you look at the first example code in my original post, you’ll see what I’m referring to. That has nothing to do with the decorators, although I’m pretty confident the change is caused by the mentioned overhaul of decorators & metadata usage.

I have no hard evidence my approach was ever correct, but it seems to be adopted by NetPad developers - so it’s not just me who used Aurelia that way.

Hopefully @Sayan751 or @bigopon could shed some light here … Thank you in advance!

Hi @migajek! Sorry for the late reply, but you are right that this behaviour is changed since beta 15. The reason is that TS does not emit the type metadata any longer when the experimental decorator is switched off. Here are some relevant links:

You need to stick to using resolve, example: resolve(IEventAggregator), until TS adds back the support for that.

@Sayan751 thanks for replying!

While I’m still not 100% sure my approach was ever supposed to work - it did, and it did work for others too (as seen in NetPad code). It also feels the natural continuation of @autoinject approach known from Aurelia 1.

I understand the decision to move forward and stick with the official standard instead of relying on experimental features, but I do admit I am disappointed with the outcome. We’re left with either duplicating the declaration of dependencies (static inject list) or explicit resolution. Either way, that leaves the gap in place of old @autoinject approach.

Frankly that also doesn’t feel the Aurelia way - looks like “convention over configuration” spirit was lost along the way :frowning:

Fingers crossed the metadata feature will become part of TS (or there will be some other approach to fill the gap) and eventually the feature will be back :crossed_fingers:

@migajek Sorry to hear that the new version is bringing trouble to you. Here are a couple of things I want to mention.

Firstly, using resolve has an inherent advantage that the property no longer needs to be a ctor argument. This is advantageous, if you use inheritance heavily, because absence of ctor arguments essentially means that the subclasses don’t have to take care of those parent ctor arguments.

Secondly, as you mentioned the conventions, we can in the convention tooling package employ a transformer to spit out the design time parameter type metadata. Which can help you with this problem. However, such transform won’t be able to cover all type-related use-cases, without essentially implementing the work that should be done by TS in the first place. Moreover, such transformers would temporary; that is, once TS adds back the support, we need to remove the transformer from the tooling package. That serves as my primary reservation to implement such transformers.

1 Like

thank you again for the reply @Sayan751 :slight_smile:

I agree using resolve on properties is suitable for inheritance heavy scenarios, however I try to rely on the ctor injection. My assumption is I am biased as I come from the .NET world :slight_smile:

I fully understand the decision not to implement custom tooling, as the right solution should rely on the TS’ standards, so again - fingers crossed for the TS team to incorporate proper metadata system.

I hope my criticism wasn’t too harsh - if it was, please take my apologies. What I’m trying to express here, is the desire to have the low-ceremony DI back - or at least ensure it’s on the roadmap - as this is one of the pieces that make Aurelia so clean and elegant.

Cheers!

@migajek No stress. Appreciate the feedback.

In the spirit of low-ceremony DI, I have opened the issue Restore dependency injection based on design-time parameter types · Issue #2001 · aurelia/aurelia · GitHub to track the progress better.

2 Likes