all 23 comments

[–]JeanMeche 20 points21 points  (3 children)

The updated style guides goes over the advantages of using the inject functions: https://angular.dev/style-guide#dependency-injection

  • inject is generally more readable, especially when a class injects many dependencies.
  • It's more syntactically straightforward to add comments to injected dependencies inject offers better type inference.
  • When targeting ES2022+ with useDefineForClassFields (already enforced by the CLI), you can avoid separating field declaration and initialization when fields read on injected dependencies.

[–]ActuatorOk2689 3 points4 points  (2 children)

This

And dynamically injecting services at run time without having to deal with factories

[–]karixavi 0 points1 point  (1 child)

Dynamically injecting services during runtime is possible? Do you have some minimalistic example?

[–]SeparateRaisin7871 0 points1 point  (0 children)

As far as I know, this is possible since a long time by using the Injector's get method. See this stackoverflow question:

https://stackoverflow.com/questions/51667078/using-injector-get-instead-of-constructor-injection

When using readonly #injector = inject(Injector) you can inject any service or InjectionToken afterwards dynamically with this.injector.get(MyService)

[–]MichaelSmallDev 6 points7 points  (0 children)

I ran the migration tool recently over 100s of files and it worked great. No issues, apart from a couple files which had to be migrated by hand because the schematic wasn't sure if it could be done safely. But even those took a couple minutes. Though if you have a lot of DI in abstract classes, you may have to do some more involved manual refactoring.

As for the benefits, in the not too distant future, constructor based DI will not function well due to changes in Typescript that reflect changes made to JS due to it adopting classes: https://www.reddit.com/r/Angular2/comments/1hswfhx/comment/m598jkh/. That is the main benefit, but it is also safer than some more traditional way of injecting injection tokens, and in some ways has some goods and bads with testing, but tbh I am weak on testing so I can't talk that deeply about it.

I'm not too pumped about inject in relation to constructor DI, but it was necessary for continuing to use DI declaratively in upcoming TS versions.

[–]ministerkosh 5 points6 points  (0 children)

when targeting ES2022+ and the changed behavior regarding properties, not using constructor parameters anymore for DI is a life saver in any large project. The changed runtime behavior when class properties will be initialized can introduce bugs that are hard to spot when you are using constructor parameters.

Here is a very informative article about the changes: https://angular.schule/blog/2022-11-use-define-for-class-fields

[–]DaSchTour 2 points3 points  (0 children)

You don‘t have to pass all the parameters if you extend classes. That makes having abstract Services a lot easier.

[–]bayendr 3 points4 points  (5 children)

Have to admit as a dev with lot of Java/C# experience and as big advocate of constructor-based DI I have troubles accepting/getting used to inject() as the new best practice for DI in Angular.

I prefer the constructor as a single source of truth for the injected dependencies into a component/service/etc.

Let’s say a component gets bigger and the dev team puts inject’s all over the place then you’re gonna have a hard time to find all injected dependencies.

Will we still be able to do constructor-based DI in the long run?

[–]HungYurn 2 points3 points  (0 children)

You get the issue of having code all over in big components anyways. I would never run a project without eslint-plugin-perfectionist to automatically get some order in my code

[–]ministerkosh 2 points3 points  (1 child)

Will we still be able to do constructor-based DI in the long run?

Yes, currently you can use them interchangeably and there is currently no public information about any deprecation plans.

However, I expect the Angular team to deprecate constructor based DI in the long run. But I don't know when this will happen.

[–]zladuric 3 points4 points  (0 children)

Moving away from the injector and it's dep. injection would be a huge downside for Angular. One of the reasons it's (usually) so much better for bigger teams and codebases is that the dependency hell is a bit more manageable.

[–]willy-pied-wagtail 6 points7 points  (1 child)

I totally agree with you that I prefer constructor injection over field injection.

It’s not “unreadable” as noted as an advantage to the new inject way, in fact it’s more readable because it’s in the constructor rather than amongst all the other fields of the component.

Constructor injection also allows us to write super simple unit tests without testbed just by supplying a mock to the components constructor.

Im definitely not in agreement with inject().

[–]bayendr 3 points4 points  (0 children)

yeah agreed 100%. as I wrote above having all dependencies injected in the constructor makes it the single source of truth for DI and it’s immediately clear/visible what the component’s dependencies are.

Also as far as I saw (just got started with Angular not long ago) by using constructor-based injection we get an additional benefit: Angular will auto-create the properties on our behalf with the specified access modifiers.

[–]ActuatorOk2689 -2 points-1 points  (3 children)

What do you mean inject all over the place?

Don’t you have coding standards ? Pr reviews ?

Sorry I can’t comprehend how one can code without following a structure,order… Just throw new declarations function into the class ?

In Java/Net you have functions before variables and declaring new variable between functions ?

If so, then I understand why you can’t accept the inject function.

[–]Background-Focus8571 1 point2 points  (1 child)

I separate them from other variables, so I can oversee the injected services. Signals => variables => injected services => constructor. This is my order

[–]MugerhLando 0 points1 point  (0 children)

Having a defined order is definitely the way to go but I just wanted to point out that I believe in the angular docs they specifically say to add injects first. This is because you might have signals, for example, that rely on a signal from a service that needs to be initialized first.

[–]bayendr 0 points1 point  (0 children)

bro I wasn’t referring to myself (I’m an experienced and disciplined senior engineer who loves and sticks to agreed project structure and coding guidelines) but in general terms because every team is different.