opaque-token – Stepan Suvorov Blog https://stepansuvorov.com/blog Release 2.0 Wed, 09 Aug 2017 08:22:22 +0000 en-US hourly 1 https://wordpress.org/?v=6.3.1 Angular: OpaqueToken или InjectionToken https://stepansuvorov.com/blog/2017/03/angular-opaquetoken-%d0%b8%d0%bb%d0%b8-injectiontoken/ https://stepansuvorov.com/blog/2017/03/angular-opaquetoken-%d0%b8%d0%bb%d0%b8-injectiontoken/#comments Sun, 19 Mar 2017 11:30:56 +0000 http://stepansuvorov.com/blog/?p=3312 Continue reading ]]> Не успели все познакомиться с понятием OpaqueToken, как оно уже становиться deprecated. Теперь нужно использовать вместо него InjectionToken.

Давайте попробуем разобраться почему.

При том, что InjectionToken несет такую же функциональность что и OpaqueToken(более того он является наследником), он еще предоставляет возможность строго задать тип инжектируемой сущности. Особенно это удобно, когда это сложный/составной тип с внутренними свойствами.

Особенно это удобно, когда вы работаете с инжектором напрямую (что довольно часто внутри самого фреймворка).

Давайте разберем пример с конфигурацией приложения, которая задается через инжектируемую сущность как значение. Для начала определим интерфейс для этого типа:

[javascript]
interface Config {
production: boolean;
base: string;
}
[/javascript]

Теперь можем создать для нашей инжектируемой сущности InjectionToken и по нему задать провайдер:

[javascript]
const APP_CONFIG = new InjectionToken<Config>(‘APP_CONFIG’);
providers: [
{
provide: APP_CONFIG,
useValue: {
production: true,
base: ”
}
}
]
[/javascript]

При инжектировании нашей сущности с помощью инжектора:

[javascript]
constructor(injector: Injector) {
const config = injector.get(APP_CONFIG);
}
[/javascript]

компилятор уже знает какого типа будет config, поэтому если мы попробуем написать что-то типа:

[javascript]
this.base = config.bese; //просто опечатались
[/javascript]

компилятор сразу выдаест ошибку: Property ‘bese’ does not exist on type ‘Config’
А в случае использования OpaqueToken ошибка не будет выявлена на этапе компиляции.
Довольно удобно, правда?
 

]]>
https://stepansuvorov.com/blog/2017/03/angular-opaquetoken-%d0%b8%d0%bb%d0%b8-injectiontoken/feed/ 3
Angular2: Opaque токены и мультипровайдеры https://stepansuvorov.com/blog/2017/01/angular2-opaque-%d1%82%d0%be%d0%ba%d0%b5%d0%bd%d1%8b-%d0%b8-%d0%bc%d1%83%d0%bb%d1%8c%d1%82%d0%b8%d0%bf%d1%80%d0%be%d0%b2%d0%b0%d0%b9%d0%b4%d0%b5%d1%80%d1%8b/ https://stepansuvorov.com/blog/2017/01/angular2-opaque-%d1%82%d0%be%d0%ba%d0%b5%d0%bd%d1%8b-%d0%b8-%d0%bc%d1%83%d0%bb%d1%8c%d1%82%d0%b8%d0%bf%d1%80%d0%be%d0%b2%d0%b0%d0%b9%d0%b4%d0%b5%d1%80%d1%8b/#comments Sat, 21 Jan 2017 18:35:12 +0000 http://stepansuvorov.com/blog/?p=3232 Continue reading ]]> При определении провайдеров рано или поздно у всех у нас возникает вопрос “А что если будет 2 провайдера с одним и тем же именем?” – Ну тут все довольно просто: последний определенный перезатрет все определенные до него.

Но что если вы подключаете сторонний модуль, а в нем уже определен провайдер с таким же именем? Очевидно, что вы его перезатрете своим. Как избежать этого?

Opaque токен

На помощь нам спешит opaque токен, который выглядит немного как костыль архитектуры. Чтобы избежать коллизии, мы заворачиваем имя нашего сервиса в объект с помощью класса OpaqueToken:

[javascript]
const MY_HTTP_TOKEN: OpaqueToken = new OpaqueToken(‘Http’);
[/javascript]

Если мы посмотрим на исходный код этого класса, то увидим всего одну строчку реализации:

[javascript]
export class OpaqueToken {
constructor(protected _desc: string) {}

toString(): string { return `Token ${this._desc}`; }
}
[/javascript]

То есть мы просто  заворачиваем наше название в объект, который в случае чего его вернет.

Что это дает? Какое бы мы дурацкое уникальное имя не придумали для своего провайдера, все равно есть вероятность, что кто-то придумает что-то подобное. А вот при создании нового объекта мы всегда гарантируем что он будет уникальный. И теперь коллизии нам не страшны – можем спокойно внедрять нашу сущность:

[javascript]
constructor(@Inject(MY_HTTP_TOKEN) private myHttp){
[/javascript]

 

Мультипровайдеры

Но представим другую ситуацию: вам внезапно захотелось запихнуть в провайдер несколько классов. Зачем? Ну вот захотелось. И чтобы для каждого класса отрабатывал механизм внедрения зависимости и получал сущность. И, да, разработчики предусмотрели и такой случай. Для этого вам нужно использовать мультипровайдеры, а именно специальное свойство multi при определении провайдера:

[javascript]
providers: [
{ provide: ‘SuperProvider’, useClass: class A {}, multi: true },
{ provide: ‘SuperProvider’, useClass: class B {}, multi: true}]
[/javascript]

И теперь можем инжектить два-в-одном:

[javascript]
constructor(@Inject(‘SuperProvider’) private testInjection) {
[/javascript]

и получить в testInjection массив из 2х сущностей: экземпляров класса A и B.

Так, еще раз – зачем это нужно? Если вы пишете библиотеку/плагин и хотите сделать его расширяемым для разработчиков, которые будут подключать ваше решение в свои приложения, думаю это именно то, что вам нужно. Именно так реализованы 2 сервиса хранящие валидаторы в ангуляре, а именно NG_VALIDATORS и NG_ASYNC_VALIDATORS, что позволяет вам добавить свои валидаторы в стандартную коллекцию:

[javascript]
{ provide: NG_VALIDATORS, useValue: (formControl) => {}, multi: true }
[/javascript]

По прежнему остается вопрос: зачем использовать задание провайдеров через строки, если это может привести к коллизии? Оставим его на совести разработчиков Angular 2.

]]>
https://stepansuvorov.com/blog/2017/01/angular2-opaque-%d1%82%d0%be%d0%ba%d0%b5%d0%bd%d1%8b-%d0%b8-%d0%bc%d1%83%d0%bb%d1%8c%d1%82%d0%b8%d0%bf%d1%80%d0%be%d0%b2%d0%b0%d0%b9%d0%b4%d0%b5%d1%80%d1%8b/feed/ 3