Skip to content

Commit

Permalink
feat(core): Add type information to injector.get() (#13785)
Browse files Browse the repository at this point in the history
- Introduce `InjectionToken<T>` which is a parameterized and type-safe
  version of `OpaqueToken`.

DEPRECATION:
- `OpaqueToken` is now deprecated, use `InjectionToken<T>` instead.
- `Injector.get(token: any, notFoundValue?: any): any` is now deprecated
  use the same method which is now overloaded as
  `Injector.get<T>(token: Type<T>|InjectionToken<T>, notFoundValue?: T): T;`.

Migration
- Replace `OpaqueToken` with `InjectionToken<?>` and parameterize it.
- Migrate your code to only use `Type<?>` or `InjectionToken<?>` as
  injection tokens. Using other tokens will not be supported in the
  future.

BREAKING CHANGE:
- Because `injector.get()` is now parameterize it is possible that code
  which used to work no longer type checks. Example would be if one
  injects `Foo` but configures it as `{provide: Foo, useClass: MockFoo}`.
  The injection instance will be that of `MockFoo` but the type will be
  `Foo` instead of `any` as in the past. This means that it was possible
  to call a method on `MockFoo` in the past which now will fail type
  check. See this example:

```
class Foo {}
class MockFoo extends Foo {
  setupMock();
}

var PROVIDERS = [
  {provide: Foo, useClass: MockFoo}
];

...

function myTest(injector: Injector) {
  var foo = injector.get(Foo);
  // This line used to work since `foo` used to be `any` before this
  // change, it will now be `Foo`, and `Foo` does not have `setUpMock()`.
  // The fix is to downcast: `injector.get(Foo) as MockFoo`.
  foo.setUpMock();
}
```

PR Close #13785
  • Loading branch information
mhevery committed Jan 17, 2017
1 parent 6d1f1a4 commit d169c24
Show file tree
Hide file tree
Showing 59 changed files with 255 additions and 175 deletions.
2 changes: 1 addition & 1 deletion modules/@angular/benchpress/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';

export {Injector, OpaqueToken, Provider, ReflectiveInjector} from '@angular/core';
export {InjectionToken, Injector, Provider, ReflectiveInjector} from '@angular/core';
export {Options} from './src/common_options';
export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
Expand Down
32 changes: 16 additions & 16 deletions modules/@angular/benchpress/src/common_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@
* found in the LICENSE file at https://angular.io/license
*/

import {OpaqueToken} from '@angular/core';
import {InjectionToken} from '@angular/core';
import * as fs from 'fs';

export class Options {
static SAMPLE_ID = new OpaqueToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
static SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription');
static FORCE_GC = new OpaqueToken('Options.forceGc');
static SAMPLE_ID = new InjectionToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new InjectionToken('Options.defaultDescription');
static SAMPLE_DESCRIPTION = new InjectionToken('Options.sampleDescription');
static FORCE_GC = new InjectionToken('Options.forceGc');
static NO_PREPARE = () => true;
static PREPARE = new OpaqueToken('Options.prepare');
static EXECUTE = new OpaqueToken('Options.execute');
static CAPABILITIES = new OpaqueToken('Options.capabilities');
static USER_AGENT = new OpaqueToken('Options.userAgent');
static MICRO_METRICS = new OpaqueToken('Options.microMetrics');
static USER_METRICS = new OpaqueToken('Options.userMetrics');
static NOW = new OpaqueToken('Options.now');
static WRITE_FILE = new OpaqueToken('Options.writeFile');
static RECEIVED_DATA = new OpaqueToken('Options.receivedData');
static REQUEST_COUNT = new OpaqueToken('Options.requestCount');
static CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
static PREPARE = new InjectionToken('Options.prepare');
static EXECUTE = new InjectionToken('Options.execute');
static CAPABILITIES = new InjectionToken('Options.capabilities');
static USER_AGENT = new InjectionToken('Options.userAgent');
static MICRO_METRICS = new InjectionToken('Options.microMetrics');
static USER_METRICS = new InjectionToken('Options.userMetrics');
static NOW = new InjectionToken('Options.now');
static WRITE_FILE = new InjectionToken('Options.writeFile');
static RECEIVED_DATA = new InjectionToken('Options.receivedData');
static REQUEST_COUNT = new InjectionToken('Options.requestCount');
static CAPTURE_FRAMES = new InjectionToken('Options.frameCapture');
static DEFAULT_PROVIDERS = [
{provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
{provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/benchpress/src/metric/multi_metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector, OpaqueToken} from '@angular/core';
import {InjectionToken, Injector} from '@angular/core';

import {Metric} from '../metric';

Expand Down Expand Up @@ -60,4 +60,4 @@ function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: strin
return result;
}

const _CHILDREN = new OpaqueToken('MultiMetric.children');
const _CHILDREN = new InjectionToken('MultiMetric.children');
4 changes: 2 additions & 2 deletions modules/@angular/benchpress/src/metric/perflog_metric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable, InjectionToken} from '@angular/core';

import {Options} from '../common_options';
import {Metric} from '../metric';
Expand All @@ -18,7 +18,7 @@ import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_e
*/
@Injectable()
export class PerflogMetric extends Metric {
static SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
static SET_TIMEOUT = new InjectionToken('PerflogMetric.setTimeout');
static PROVIDERS = [
PerflogMetric, {
provide: PerflogMetric.SET_TIMEOUT,
Expand Down
6 changes: 3 additions & 3 deletions modules/@angular/benchpress/src/reporter/console_reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable, InjectionToken} from '@angular/core';
import {print} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
Expand All @@ -20,8 +20,8 @@ import {formatNum, formatStats, sortedProps} from './util';
*/
@Injectable()
export class ConsoleReporter extends Reporter {
static PRINT = new OpaqueToken('ConsoleReporter.print');
static COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
static PRINT = new InjectionToken('ConsoleReporter.print');
static COLUMN_WIDTH = new InjectionToken('ConsoleReporter.columnWidth');
static PROVIDERS = [
ConsoleReporter, {provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18},
{provide: ConsoleReporter.PRINT, useValue: print}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable, InjectionToken} from '@angular/core';

import {Options} from '../common_options';
import {MeasureValues} from '../measure_values';
Expand All @@ -21,7 +21,7 @@ import {formatStats, sortedProps} from './util';
*/
@Injectable()
export class JsonFileReporter extends Reporter {
static PATH = new OpaqueToken('JsonFileReporter.path');
static PATH = new InjectionToken('JsonFileReporter.path');
static PROVIDERS = [JsonFileReporter, {provide: JsonFileReporter.PATH, useValue: '.'}];

constructor(
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/benchpress/src/reporter/multi_reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector, OpaqueToken} from '@angular/core';
import {InjectionToken, Injector} from '@angular/core';

import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
Expand Down Expand Up @@ -39,4 +39,4 @@ export class MultiReporter extends Reporter {
}
}

const _CHILDREN = new OpaqueToken('MultiReporter.children');
const _CHILDREN = new InjectionToken('MultiReporter.children');
2 changes: 1 addition & 1 deletion modules/@angular/benchpress/src/sample_description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {OpaqueToken} from '@angular/core';
import {InjectionToken} from '@angular/core';

import {Options} from './common_options';
import {Metric} from './metric';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable, InjectionToken} from '@angular/core';

import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
Expand All @@ -18,8 +18,8 @@ import {Validator} from '../validator';
*/
@Injectable()
export class RegressionSlopeValidator extends Validator {
static SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
static METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
static SAMPLE_SIZE = new InjectionToken('RegressionSlopeValidator.sampleSize');
static METRIC = new InjectionToken('RegressionSlopeValidator.metric');
static PROVIDERS = [
RegressionSlopeValidator, {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: 10},
{provide: RegressionSlopeValidator.METRIC, useValue: 'scriptTime'}
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/benchpress/src/validator/size_validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable, InjectionToken} from '@angular/core';

import {MeasureValues} from '../measure_values';
import {Validator} from '../validator';
Expand All @@ -16,7 +16,7 @@ import {Validator} from '../validator';
*/
@Injectable()
export class SizeValidator extends Validator {
static SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
static SAMPLE_SIZE = new InjectionToken('SizeValidator.sampleSize');
static PROVIDERS = [SizeValidator, {provide: SizeValidator.SAMPLE_SIZE, useValue: 10}];

constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); }
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/benchpress/src/web_driver_extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector, OpaqueToken} from '@angular/core';
import {InjectionToken, Injector} from '@angular/core';

import {Options} from './common_options';

Expand Down Expand Up @@ -101,4 +101,4 @@ export class PerfLogFeatures {
}
}

const _CHILDREN = new OpaqueToken('WebDriverExtension.children');
const _CHILDREN = new InjectionToken('WebDriverExtension.children');
4 changes: 2 additions & 2 deletions modules/@angular/common/src/location/location_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {OpaqueToken} from '@angular/core';
import {InjectionToken} from '@angular/core';
import {LocationChangeListener} from './platform_location';

/**
Expand Down Expand Up @@ -61,4 +61,4 @@ export abstract class LocationStrategy {
*
* @stable
*/
export const APP_BASE_HREF: OpaqueToken = new OpaqueToken('appBaseHref');
export const APP_BASE_HREF = new InjectionToken<string>('appBaseHref');
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {CommonModule} from '@angular/common';
import {NgComponentOutlet} from '@angular/common/src/directives/ng_component_outlet';
import {Component, ComponentRef, Inject, Injector, NO_ERRORS_SCHEMA, NgModule, OpaqueToken, Optional, Provider, QueryList, ReflectiveInjector, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
import {Component, ComponentRef, Inject, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, Optional, Provider, QueryList, ReflectiveInjector, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
import {TestBed, async} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';

Expand Down Expand Up @@ -146,7 +146,7 @@ export function main() {
});
}

const TEST_TOKEN = new OpaqueToken('TestToken');
const TEST_TOKEN = new InjectionToken('TestToken');
@Component({selector: 'injected-component', template: 'foo'})
class InjectedComponent {
constructor(@Optional() @Inject(TEST_TOKEN) public testToken: any) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Inject, OpaqueToken} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Inject, InjectionToken} from '@angular/core';

import {BasicComp} from './basic';

Expand All @@ -15,7 +15,7 @@ export class CompWithEntryComponents {
constructor(public cfr: ComponentFactoryResolver) {}
}

export const SOME_TOKEN = new OpaqueToken('someToken');
export const SOME_TOKEN = new InjectionToken('someToken');

export function provideValueWithEntryComponents(value: any) {
return [
Expand Down
8 changes: 4 additions & 4 deletions modules/@angular/compiler-cli/integrationtest/src/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
*/

import * as common from '@angular/common';
import {CUSTOM_ELEMENTS_SCHEMA, Component, Directive, EventEmitter, Inject, NgModule, OpaqueToken, Output} from '@angular/core';
import {CUSTOM_ELEMENTS_SCHEMA, Component, Directive, EventEmitter, Inject, InjectionToken, NgModule, Output} from '@angular/core';
import {Observable} from 'rxjs/Observable';

import {wrapInArray} from './funcs';

export const SOME_OPAQUE_TOKEN = new OpaqueToken('opaqueToken');
export const SOME_INJECTON_TOKEN = new InjectionToken('injectionToken');

@Component({
selector: 'comp-providers',
template: '',
providers: [
{provide: 'strToken', useValue: 'strValue'},
{provide: SOME_OPAQUE_TOKEN, useValue: 10},
{provide: SOME_INJECTON_TOKEN, useValue: 10},
{provide: 'reference', useValue: common.NgIf},
{provide: 'complexToken', useValue: {a: 1, b: ['test', SOME_OPAQUE_TOKEN]}},
{provide: 'complexToken', useValue: {a: 1, b: ['test', SOME_INJECTON_TOKEN]}},
]
})
export class CompWithProviders {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {LowerCasePipe, NgIf} from '@angular/common';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Directive, Inject, Injectable, Input, ModuleWithProviders, NgModule, OpaqueToken, Pipe} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Directive, Inject, Injectable, InjectionToken, Input, ModuleWithProviders, NgModule, Pipe} from '@angular/core';

@Injectable()
export class SomeService {
Expand Down Expand Up @@ -48,7 +48,7 @@ export class CompUsingRootModuleDirectiveAndPipe {
export class CompUsingLibModuleDirectiveAndPipe {
}

export const SOME_TOKEN = new OpaqueToken('someToken');
export const SOME_TOKEN = new InjectionToken('someToken');

export function provideValueWithEntryComponents(value: any) {
return [
Expand Down
22 changes: 13 additions & 9 deletions modules/@angular/compiler/src/aot/static_reflector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const ANGULAR_IMPORT_LOCATIONS = {
coreDecorators: '@angular/core/src/metadata',
diDecorators: '@angular/core/src/di/metadata',
diMetadata: '@angular/core/src/di/metadata',
diOpaqueToken: '@angular/core/src/di/opaque_token',
diInjectionToken: '@angular/core/src/di/injection_token',
diOpaqueToken: '@angular/core/src/di/injection_token',
animationMetadata: '@angular/core/src/animation/metadata',
provider: '@angular/core/src/di/provider'
};
Expand All @@ -34,6 +35,7 @@ export class StaticReflector implements ReflectorReader {
private parameterCache = new Map<StaticSymbol, any[]>();
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
private injectionToken: StaticSymbol;
private opaqueToken: StaticSymbol;

constructor(
Expand Down Expand Up @@ -229,9 +231,10 @@ export class StaticReflector implements ReflectorReader {
}

private initializeConversionMap(): void {
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
ANGULAR_IMPORT_LOCATIONS;
this.opaqueToken = this.findDeclaration(diOpaqueToken, 'OpaqueToken');
const {coreDecorators, diDecorators, diMetadata, diInjectionToken,
diOpaqueToken, animationMetadata, provider} = ANGULAR_IMPORT_LOCATIONS;
this.injectionToken = this.findDeclaration(diInjectionToken, 'InjectionToken');
this.opaqueToken = this.findDeclaration(diInjectionToken, 'OpaqueToken');

this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Host'), Host);
this._registerDecoratorOrConstructor(
Expand Down Expand Up @@ -382,7 +385,8 @@ export class StaticReflector implements ReflectorReader {
}
if (expression instanceof StaticSymbol) {
// Stop simplification at builtin symbols
if (expression === self.opaqueToken || self.conversionMap.has(expression)) {
if (expression === self.injectionToken || expression === self.opaqueToken ||
self.conversionMap.has(expression)) {
return expression;
} else {
const staticSymbol = expression;
Expand Down Expand Up @@ -506,9 +510,9 @@ export class StaticReflector implements ReflectorReader {
// Determine if the function is a built-in conversion
staticSymbol = simplifyInContext(context, expression['expression'], depth + 1);
if (staticSymbol instanceof StaticSymbol) {
if (staticSymbol === self.opaqueToken) {
// if somebody calls new OpaqueToken, don't create an OpaqueToken,
// but rather return the symbol to which the OpaqueToken is assigned to.
if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
// if somebody calls new InjectionToken, don't create an InjectionToken,
// but rather return the symbol to which the InjectionToken is assigned to.
return context;
}
const argExpressions: any[] = expression['arguments'] || [];
Expand Down Expand Up @@ -674,4 +678,4 @@ function positionalError(message: string, fileName: string, line: number, column
(result as any).line = line;
(result as any).column = column;
return result;
}
}
4 changes: 2 additions & 2 deletions modules/@angular/compiler/src/jit/compiler_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, OpaqueToken, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, InjectionToken, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';

import {AnimationParser} from '../animation/animation_parser';
import {CompilerConfig} from '../config';
Expand Down Expand Up @@ -40,7 +40,7 @@ const _NO_RESOURCE_LOADER: ResourceLoader = {
`No ResourceLoader implementation has been provided. Can't read the url "${url}"`);}
};

const baseHtmlParser = new OpaqueToken('HtmlParser');
const baseHtmlParser = new InjectionToken('HtmlParser');

/**
* A set of providers that provide `JitCompiler` and its dependencies to use for
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/compiler/src/metadata_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, ComponentFactory, Directive, Host, Inject, Injectable, ModuleWithProviders, OpaqueToken, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, ComponentFactory, Directive, Host, Inject, Injectable, InjectionToken, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';

import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol';
import {ngfactoryFilePath} from './aot/util';
Expand All @@ -27,7 +27,7 @@ import {getUrlScheme} from './url_resolver';
import {MODULE_SUFFIX, SyntaxError, ValueTransformer, visitValue} from './util';

export type ErrorCollector = (error: any, type?: any) => void;
export const ERROR_COLLECTOR_TOKEN = new OpaqueToken('ErrorCollector');
export const ERROR_COLLECTOR_TOKEN = new InjectionToken('ErrorCollector');

// Design notes:
// - don't lazily create metadata:
Expand Down
Loading

1 comment on commit d169c24

@mhevery
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment for case where the .d.ts file import needs to change from OpaqueToken to InjectionToken.

Please sign in to comment.