Angular DI и наследование: внедрение расширений базового сервиса - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть базовая служба и две службы наследования:

@Injectable({ providedIn: 'root' })
export class BaseService {
  foo(src?: string){
    return `speaking from ${src || 'BaseService'}`;
  }
}


@Injectable({ providedIn: 'root' })
export class SomeService extends BaseService {
  foo(){
    return super.foo('SomeService')
  }
}

@Injectable({ providedIn: 'root' })
export class AnotherService extends BaseService {
  foo(){
    return super.foo('AnotherService')
  }
}

Я хочу внедрить их в некоторый компонент и получить экземпляры трех отдельных классов:

@Component({
    selector: 'my-app',
    template: `
        <div>
            <p>Who's there?</p>
            <p>{{ base }}</p>
            <p>{{ some }}</p>
            <p>{{ another }}</p>

        </div>
    `,
})
export class App {
    base: string;
    some: string;
    another: string;

    constructor(base: BaseService, some: SomeService, another: AnotherService) {
        this.base = base.foo();
        this.some = some.foo();
        this.another = another.foo();

    }
}

Вместо этогоЯ получаю три экземпляра одного класса (вывод HTML):

Who's there?

speaking from BaseService

speaking from BaseService

speaking from BaseService
  • Почему это не работает?
  • Почему SomeService, AnotherService и BaseService не являются уникальными токенами для Angular DI?

Похоже, что включение

...    
{ provide: SomeService , useClass: SomeService },
{ provide: AnotherService , useClass: AnotherService },
...

в провайдерах заставит его работать.

  • Зачем это нужно явно?

A plnkr: https://next.plnkr.co/edit/BvmppLHRbFbz9CFZ

1 Ответ

0 голосов
/ 22 сентября 2018

SomeService и AnotherService наследуют метаданные декоратора от BaseService, поэтому angular вставляет на их место экземпляр BaseService.

Это опасно, так как вызов любого члена экземпляра из SomeService или AnotherService, который не наследуется от BaseService, вызовет ошибку во время выполнения.

Самый простой способ архивировать искомое поведение - это наследовать от общего абстрактного базового класса,без декоратора:

export abstract class AbstractBaseService {
  foo(src?: string) {
    return `speaking from ${src || 'AbstractBaseService'}`;
  }
}

@Injectable({ providedIn: 'root' })
export class BaseService extends AbstractBaseService {
  foo() {
    return super.foo('BaseService');
  }
}

@Injectable({ providedIn: 'root'})
export class SomeService extends AbstractBaseService {
  foo() {
    return super.foo('SomeService');
  }
}

@Injectable({ providedIn: 'root' })
export class AnotherService extends AbstractBaseService {
  foo() {
    return super.foo('AnotherService');
  }
}

I изменил ваш plnkr для проверки этого подхода.

...