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

typed provide #55054

Closed
SeregPie opened this issue Mar 26, 2024 · 2 comments
Closed

typed provide #55054

SeregPie opened this issue Mar 26, 2024 · 2 comments

Comments

@SeregPie
Copy link

SeregPie commented Mar 26, 2024

Which @angular/* package(s) are relevant/related to the feature request?

core

Description

Actually the providers are not typed. It is easy to make a mistake when you provide something.

It would be nice to write the providers like this.

type AppConfig = {
  foo: string;
  bar: number;
};

const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');

@Component({
  providers: [provide(APP_CONFIG).useValue({foo: 'abc', bar: 123})]
})

const APP_CONFIGS = new InjectionToken<Array<AppConfig>>('APP_CONFIGS');

@Component({
  providers: [
    provide(APP_CONFIGS).useValue([{foo: 'abc', bar: 123}]),
    // or
    provide(APP_CONFIGS, {multi: true}).useValue({foo: 'abc', bar: 123}),
  ],
})

Proposed solution

It could be done with something like this.

export type ProviderChoice<T> = {
  useValue(src: T): ValueProvider;
  useFactory(src: {(): T}): FactoryProvider;
  useClass(src: Type<T>): ClassProvider;
  useExisting(src: ProviderToken<T>): ExistingProvider;
};

export type ProvideOptions = {
  multi?: boolean;
};

export function provide<T>(token: ProviderToken<T>): ProviderChoice<T>;

export function provide<T>(
  token: ProviderToken<Array<T>>,
  options: ProvideOptions & {multi: true},
): ProviderChoice<T>;

export function provide<T>(
  token: ProviderToken<T>,
  options: ProvideOptions & {multi: false},
): ProviderChoice<T>;

export function provide<T>(
  token: ProviderToken<T>,
  {multi = false}: ProvideOptions = {},
): ProviderChoice<T> {
  const options = {
    provide: token,
    multi,
  };
  return {
    useValue: (src) => ({...options, useValue: src}),
    useFactory: (src) => ({...options, useFactory: src}),
    useClass: (src) => ({...options, useClass: src}),
    useExisting: (src) => ({...options, useExisting: src}),
  };
}

I think the support of deps is not necessary because of the inject function.


There is only one problem with this.

provide(APP_CONFIG, {multi: true});

The type should fail but it does not, because of this.

Alternatives considered

Alternative is to keep to use any in a provider object.

@JoostK
Copy link
Member

JoostK commented Mar 26, 2024

This is being tracked in #33883.

@JoostK JoostK closed this as not planned Won't fix, can't repro, duplicate, stale Mar 26, 2024
@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 Apr 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants