Абстрагирование @Injectable с Angular Плющ не работает - PullRequest
3 голосов
/ 09 января 2020

Обновление

Введение

В Angular Услуги предоставляются использование декоратора @Injectable.

@Injectable() // -> works
export class MyService {
  constructor() {}
}

Abstracting @ Injectable

До Ivy можно было создать абстракцию для @Injectable (например, для динамической настройки провайдера, улучшения сервиса класс).

В следующем фрагменте показан пример того, как можно обернуть @Injectable.

function InjectableEnhanced() {
  return <T extends new (...args: any[]) => InstanceType<T>>(target: T) => {
    Injectable({ providedIn: "root" })(target);
  };
}

Использование декоратора InjectableEnhanced (см. выше) не работает, когда включен Ivy. Следующий фрагмент кода вызывает ошибку времени выполнения.

@InjectableEnhanced() // -> does not work
export class MyService {
  constructor() {}
}

Ошибка времени выполнения

Компиляция службы с использованием @InjectableEnhanced с angular / cli работает, но в браузере отображается следующая ошибка. Соответствующий проект можно найти по адресу https://github.com/GregOnNet/ng-9-inject.git.

enter image description here

Возможно, компилятор Angular выполняет некоторое преобразование кода, но больше не может разрешать @Injectable внутри других декораторов. Взглянув на репозиторий angular, ссылку на JIT-компилятор можно найти в injectable.ts (см .: https://github.com/angular/angular/blob/master/packages/core/src/di/injectable.ts#L14).

Вопрос

Есть ли еще способ абстрагирования @Injectable?

Репозиторий для воспроизведения

https://github.com/GregOnNet/ng-9-inject.git

Ответы [ 2 ]

3 голосов
/ 15 января 2020

Пользовательский поставщик может быть создан с использованием некоторого внутреннего API angular:

import { ɵɵdefineInjectable, ɵɵinject } from "@angular/core";

export function InjectableEnhanced() {
  return <T extends new (...args: any[]) => InstanceType<T>>(target: T) => {
    (target as any).ɵfac = function() {
      throw new Error("cannot create directly");
    };

    (target as any).ɵprov = ɵɵdefineInjectable({
      token: target,
      providedIn: "root",
      factory() {
        // ɵɵinject can be used to get dependency being already registered
        const dependency = ɵɵinject(Dependency); 
        return new target(dependency);
      }
    });
    return target;
  };
}

Рабочий пример можно найти по адресу https://github.com/GregOnNet/ng-9-inject

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

Декоратор подключается к конструктору, как и ожидалось, но когда создается AppComponent, инжектор пытается разрешить провайдер и вылетает.

Я думаю, что сообщение об ошибке является просто обобщенным c ошибка, когда компонент не удается создать, но ошибка возникает, когда Angular пытается получить инъекции для конструктора AppComponent.

Если вы зарегистрируете конструктор для службы, вы увидите, что поставщик метаданные были прикреплены:

@InjectableEnhanced()
export class MyService {
  constructor() {
  }
}


console.log((MyService as object).prototype.constructor.hasOwnProperty('ɵprov'));
// prints "true"

Когда я пытаюсь проверить это свойство, оно вызывает ошибку:

try {
  console.log((MyService as object).prototype.constructor.ɵprov);
} catch (err) {
  console.log(err); // prints the same error message
}

Я думаю, что это свойство getter , которое разрешается к экземпляру провайдера, и именно это приводит к сбою.

Самая близкая проблема на Angular, которую я мог найти, была эта, но она все еще открыта:

https://github.com/angular/angular/issues/31495

Так что я чувствую, что компилятор Ivy может искать в исходном коде @Injectable() и формировать список ожидаемых провайдеров, и он не видит этот новый декоратор поэтому MyService исключен из списка. Позже во время выполнения метаданные для декоратора есть, но инжектор не знает, для чего он, и вылетает.

Я попытался найти что-то задокументированное, где вы могли бы зарегистрировать новый декоратор с помощью компилятора Ivy. , но не смог, и я не знаю, существует ли такая вещь.

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

...