Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): introduce EnvironmentProviders wrapper type #47669

Closed
wants to merge 4 commits into from

Conversation

alxhub
Copy link
Member

@alxhub alxhub commented Oct 5, 2022

feat(core): introduce EnvironmentProviders wrapper type

This commit introduces a new type EnvironmentProviders which can be used
in contexts where Angular accepted Providers destined for
EnvironmentInjectors. This includes contexts such as @NgModule.providers
and Route.providers.

The new type is useful for preventing such providers from accidentally
ending up in @Component.providers. It can be used as the return type of
provider functions (such as provideRouter) to enforce this safety.

Because Provider allows any[] nested arrays, the compile-time safety
provided by EnvironmentProviders is easily circumvented. However, the
runtime shape of EnvironmentProviders is not compatible with component
injectors and will result in a runtime error if it leaks through (NG0207).

A new function makeEnvironmentProviders is used to construct this new type
from an array of providers.

The existing importProvidersFrom operation previously returned a very
similar type ImportedNgModuleProviders which had the same goal. This
machinery is switched over to use the new EnvironmentProviders interface
instead (in fact, ImportedNgModuleProviders is now just an alias to
EnvironmentProviders).

@alxhub alxhub added this to the v15 feature freeze blockers milestone Oct 5, 2022
@ngbot ngbot bot removed this from the v15 feature freeze blockers milestone Oct 5, 2022
@pullapprove pullapprove bot requested a review from atscott October 5, 2022 20:21
@angular-robot angular-robot bot added the feature Issue that requests a new feature label Oct 5, 2022
@alxhub alxhub force-pushed the v15/core/env-providers branch 2 times, most recently from 99c2702 to e953d3d Compare October 5, 2022 20:30
@atscott atscott requested review from AndrewKushnir and removed request for atscott October 5, 2022 20:43
@alxhub alxhub added cla: yes target: major This PR is targeted for the next major release labels Oct 5, 2022
@alxhub alxhub force-pushed the v15/core/env-providers branch 2 times, most recently from fa5888f to 1f63122 Compare October 5, 2022 22:51
This commit introduces the `EnvironmentProviders` interface, but does not
yet export it as public API.
This commit modifies `R3Injector` and other code in Angular that deals with
providers, to handle `EnvironmentProviders` objects as well as normal
`Provider` types. There is no user-visible impact to this change, but it
prepares the core of the DI system for the introduction of
`EnvironmentProviders` as a public feature.
This commit introduces a new type `EnvironmentProviders` which can be used
in contexts where Angular accepted `Provider`s destined for
`EnvironmentInjector`s. This includes contexts such as `@NgModule.providers`
and `Route.providers`.

The new type is useful for preventing such providers from accidentally
ending up in `@Component.providers`. It can be used as the return type of
provider functions (such as `provideRouter`) to enforce this safety.

Because `Provider` allows `any[]` nested arrays, the compile-time safety
provided by `EnvironmentProviders` is easily circumvented. However, the
runtime shape of `EnvironmentProviders` is not compatible with component
injectors and will result in a runtime error if it leaks through (NG0207).

A new function `makeEnvironmentProviders` is used to construct this new type
from an array of providers.

The existing `importProvidersFrom` operation previously returned a very
similar type `ImportedNgModuleProviders` which had the same goal. This
machinery is switched over to use the new `EnvironmentProviders` interface
instead (in fact, `ImportedNgModuleProviders` is now just an alias to
`EnvironmentProviders`).
This commit switches `provideRouter()` to return the new
`EnvironmentProviders` wrapper type, preventing it from being accidentally
(or intentionally) included in `@Component.providers`.
@jessicajaniuk jessicajaniuk added the area: core Issues related to the framework runtime label Oct 6, 2022
@ngbot ngbot bot added this to the Backlog milestone Oct 6, 2022
Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great 👍

ɵbrand: 'EnvironmentProviders';
};

export interface InternalEnvironmentProviders extends EnvironmentProviders {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: may be add a quick comment on why we need this type (I think it's covered in the ɵfromNgModule field description, may be just add a version of it as a comment about this function)?

Comment on lines +28 to +29
* Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
* referenced in `@Component in a component injector.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
* referenced in `@Component in a component injector.
* Wrap an array of `Provider`s into `EnvironmentProviders`, preventing them from being accidentally
* referenced in `@Component` or `@Directive` in a component injector.

deepForEach(defProviders, provider => {
ngDevMode && validateProvider(provider, defProviders as SingleProvider[], injectorType);
providersOut.push(provider);
deepForEachProvider(defProviders, provider => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious if we can type it here (vs adding as)?

Suggested change
deepForEachProvider(defProviders, provider => {
deepForEachProvider(defProviders, (provider: SingleProvider) => {

Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed-for: public-api

@pullapprove pullapprove bot requested a review from dylhunn October 7, 2022 19:11
Copy link
Contributor

@jessicajaniuk jessicajaniuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed-for: public-api

@jessicajaniuk jessicajaniuk removed the request for review from pkozlowski-opensource October 7, 2022 20:48
@jessicajaniuk jessicajaniuk removed the request for review from dylhunn October 7, 2022 20:48
@jessicajaniuk jessicajaniuk added the action: merge The PR is ready for merge by the caretaker label Oct 7, 2022
@jessicajaniuk
Copy link
Contributor

This PR was merged into the repository by commit 07017a7.

jessicajaniuk pushed a commit that referenced this pull request Oct 7, 2022
This commit modifies `R3Injector` and other code in Angular that deals with
providers, to handle `EnvironmentProviders` objects as well as normal
`Provider` types. There is no user-visible impact to this change, but it
prepares the core of the DI system for the introduction of
`EnvironmentProviders` as a public feature.

PR Close #47669
jessicajaniuk pushed a commit that referenced this pull request Oct 7, 2022
This commit introduces a new type `EnvironmentProviders` which can be used
in contexts where Angular accepted `Provider`s destined for
`EnvironmentInjector`s. This includes contexts such as `@NgModule.providers`
and `Route.providers`.

The new type is useful for preventing such providers from accidentally
ending up in `@Component.providers`. It can be used as the return type of
provider functions (such as `provideRouter`) to enforce this safety.

Because `Provider` allows `any[]` nested arrays, the compile-time safety
provided by `EnvironmentProviders` is easily circumvented. However, the
runtime shape of `EnvironmentProviders` is not compatible with component
injectors and will result in a runtime error if it leaks through (NG0207).

A new function `makeEnvironmentProviders` is used to construct this new type
from an array of providers.

The existing `importProvidersFrom` operation previously returned a very
similar type `ImportedNgModuleProviders` which had the same goal. This
machinery is switched over to use the new `EnvironmentProviders` interface
instead (in fact, `ImportedNgModuleProviders` is now just an alias to
`EnvironmentProviders`).

PR Close #47669
jessicajaniuk pushed a commit that referenced this pull request Oct 7, 2022
)

This commit switches `provideRouter()` to return the new
`EnvironmentProviders` wrapper type, preventing it from being accidentally
(or intentionally) included in `@Component.providers`.

PR Close #47669
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime cla: yes feature Issue that requests a new feature target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants