Angular Литералы ValueProvider и Injector, используемые в объявлении поставщиков компонентов и модулей - PullRequest
2 голосов
/ 13 января 2020

Я предоставляю некоторые значения констант через ValueProvider, и я немного удивлен семантией c различий между ClassProvider & ValueProvider.

Мой текущий ValueProvider выглядит следующим образом:

Определение провайдера:

export const DeliveryChangeTextToken = new InjectionToken<DeliveryTextsAndConditionsIfc[]>('Provides text option values for delivery component');

export const DELIVERY_CHANGE_TEXT_PROVIDER: ValueProvider = {
    provide: DeliveryChangeTextToken,
    useValue: /* Here is object literal or imported value, whatever */
}

Теперь внутри модуля я добавляю нового провайдера в массив провайдеров:

providers: [DELIVERY_CHANGE_TEXT_PROVIDER]

И я использую его как компонент итак:

constructor(@Inject(DeliveryChangeTextToken) texts: DeliveryTextsAndConditionsIfc[])
{ this.specialTxtConditions = texts; }

Работает и нормально, но я немного обеспокоен этими Provider массивом и конструктором @Inject фигур.

В объявлении модуля используется форма Provider[], который является литералом поставщика, состоящим из provide, useValue и multi полей sob, все они заключены в DELIVERY_CHANGE_TEXT_PROVIDER. Просто и элегантно.

Но для доступа к нему внутри компонента ему нужно предоставить @Inject(), который принимает тип токена, в моем случае это DeliveryChangeTextToken.

Это немного сбивает с толку и требует перехода между 3 файлами, чтобы увидеть, какое значение под каким токеном фактически предоставляется и отличается от того, как ClassProvider, самый распространенный провайдер каждый раз используется под одним и тем же именем в коде:

Сервис:

@Injectable()
export class Service{}

Модуль:

provide: [Service]

Компонент:

constructor(private service: Service)

Есть ли способ обеспечить согласованность между декларацией поставщика и фактической семантикой ввода DI?

И, возможно, дополнительный вопрос, что за волшебные c @Injectable() на самом деле делают, чтобы сделать так, чтобы ClassProvider s работал?

EDIT: Развертывание литерала объекта провайдера, конечно, вариант, чтобы обеспечить sam-форму в обоих местах, но я бы предпочел использовать более короткую форму Provider в обоих местах, чем более длинную раздутую форму литерала поставщика:

providers: [
  {
    provide: DeliveryChangeTextToken, useValue: /* Here is object literal or imported value, whatever */
  }
]

1 Ответ

1 голос
/ 13 января 2020

Это интересная проблема. Я рад, что вы это выделили.

Чтобы добиться согласованности в таких случаях, ИМО, вы можете использовать абстрактный класс для определения формы объекта. Это также позволит вам избавиться от @Inject декоратора.

export abstract class CurrentUser {
  role: string;
  id: string;
  name: string;
}
const currentUserLiteral: CurrentUser = {
  id: '123',
  name: 'andrei',
  role: 'admin',
};

@NgModule({
  imports: [
    BrowserModule
  ],
  declarations: [
    AppComponent
  ],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: CurrentUser,
      useValue: currentUserLiteral,
    },
  ]
})
export class AppModule { }
@Component({
   /* ... */
})
export class AppComponent {
  constructor (
    private crtUser: CurrentUser,
  ) {
    console.log(crtUser.name); // 'andrei'
  }
}

crtUser также получит правильные типы.

AFAIK, @Injectable() светится, когда ваш класс внедряет и другие зависимости.

Если у вашего класса их нет, вы можете избежать этого, даже если рекомендуется всегда его использовать.

// Does not have any injected dependencies!
export class InjectableWithoutDecorator {
  private name = 'andrei';

  constructor () { }

  getNameUpperCase () {
    return this.name.toUpperCase();
  }
}
@NgModule({
  /* ... */
  providers: [
    InjectableWithoutDecorator,
  ]
})
export class AppModule { }
@Component({
  /* ... */
})
export class AppComponent {
  constructor (
    private withoutDecorator: InjectableWithoutDecorator,
  ) {
    console.log(withoutDecorator.getNameUpperCase()); // 'ANDREI'
  }
}

Вы не можете использовать такой абстрактный класс

@NgModule({
  /* ... */
  providers: [AbstractClass]
})

, потому что абстрактные классы не являются экземплярами сами по себе. Их можно использовать через свои подклассы.

нг-беговая игровая площадка .

...