Skip to the solution
HardFrontend7 min read

What is the difference between useClass, useValue, useFactory, and useExisting?

441 views

The problem

Question presented to candidate: "In a providers array I see useClass, useValue, useFactory and useExisting. Explain what each one does and give a real situation where you would pick it."

What a strong answer should cover:

  • A provider is { provide: TOKEN, <recipe> }; the recipe says how the value for that token is produced, and the result is cached per injector.
  • useClass: instantiate this class (possibly a different one than the token), e.g. a mock or an environment-specific implementation. The bare [MyService] shorthand means { provide: MyService, useClass: MyService }.
  • useValue: hand over this exact value, no construction: config objects, constants, test fakes.
  • useFactory: run a function to decide or build the value; it can call inject() (or use the older deps array) and runs once per injector.
  • useExisting: an alias: the token resolves to whatever another token resolves to, the same instance, not a copy. Contrast with useClass, which builds a new instance under the second token.
  • multi: true combines with any recipe to build a list.

Clarifying questions expected:

  • "Is the alternative implementation chosen at build time, at startup, or per subtree?"

Code / implementation expected: Yes β€” all four recipes with instance identity checked.

  • di
  • providers

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 9 sections

Read the code

AngularAll four recipes side by side, with instance ids proving which ones share
import { Component, InjectionToken, inject } from "@angular/core";

let made = 0;

// The token the app asks for. Abstract class = a type AND a runtime token.
export abstract class Storage {
  abstract readonly kind: string;
  readonly id = ++made;
}
export class MemoryStorage extends Storage { readonly kind = "memory"; }
export class LoggingStorage extends Storage { readonly kind = "logging"; }

export const APP_NAME = new InjectionToken<string>("APP_NAME");
export const IS_DEV = new InjectionToken<boolean>("IS_DEV");
export const LEGACY_STORAGE = new InjectionToken<Storage>("LEGACY_STORAGE");
export const SECOND_MEMORY = new InjectionToken<MemoryStorage>("SECOND_MEMORY");

@Component({
  selector: "app-root",
  providers: [
    { provide: IS_DEV, useValue: true },                       // useValue: hand over this exact value
    { provide: APP_NAME, useValue: "Shop" },
    { provide: MemoryStorage, useClass: MemoryStorage },        // same as just MemoryStorage
    {
      provide: Storage,                                         // useFactory: run code to decide
      useFactory: () => (inject(IS_DEV) ? new LoggingStorage() : inject(MemoryStorage)),
    },
    { provide: LEGACY_STORAGE, useExisting: Storage },          // useExisting: an alias, no new instance
    { provide: SECOND_MEMORY, useClass: MemoryStorage },        // useClass under another token: a NEW instance
  ],
  template: `
    <p>{{ name }} storage: {{ storage.kind }} #{{ storage.id }}</p>
    <p>legacy alias: {{ legacy.kind }} #{{ legacy.id }} same object: {{ legacy === storage }}</p>
    <p>MemoryStorage #{{ memory.id }} vs SECOND_MEMORY #{{ second.id }} same: {{ memory === second }}</p>
    <p>instances created: {{ count }}</p>
  `,
})
export class AppComponent {
  name = inject(APP_NAME);
  storage = inject(Storage);
  legacy = inject(LEGACY_STORAGE);
  memory = inject(MemoryStorage);
  second = inject(SECOND_MEMORY);
  count = made;
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 106 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextHard

What is the difference between afterRender and afterNextRender lifecycle hooks?

Continue