diff --git a/modules/angular2/change_detection.ts b/modules/angular2/change_detection.ts index a4f1d68abd..5e2ff02e38 100644 --- a/modules/angular2/change_detection.ts +++ b/modules/angular2/change_detection.ts @@ -25,8 +25,8 @@ export { } from './src/change_detection/exceptions'; export { ProtoChangeDetector, - ChangeDispatcher, ChangeDetector, + ChangeDispatcher, ChangeDetection, ChangeDetectorDefinition } from './src/change_detection/interfaces'; diff --git a/modules/angular2/src/change_detection/abstract_change_detector.ts b/modules/angular2/src/change_detection/abstract_change_detector.ts index 479f83df86..3b51309d58 100644 --- a/modules/angular2/src/change_detection/abstract_change_detector.ts +++ b/modules/angular2/src/change_detection/abstract_change_detector.ts @@ -2,19 +2,17 @@ import {isPresent} from 'angular2/src/facade/lang'; import {List, ListWrapper} from 'angular2/src/facade/collection'; import {ChangeDetectorRef} from './change_detector_ref'; import {ChangeDetector} from './interfaces'; +import {Locals} from './parser/locals'; import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; -export class AbstractChangeDetector extends ChangeDetector { +export class AbstractChangeDetector implements ChangeDetector { lightDomChildren: List = []; shadowDomChildren: List = []; parent: ChangeDetector; mode: string = null; ref: ChangeDetectorRef; - constructor() { - super(); - this.ref = new ChangeDetectorRef(this); - } + constructor(public id: string) { this.ref = new ChangeDetectorRef(this); } addChild(cd: ChangeDetector): void { this.lightDomChildren.push(cd); @@ -51,6 +49,11 @@ export class AbstractChangeDetector extends ChangeDetector { } detectChangesInRecords(throwOnChange: boolean): void {} + + hydrate(context: any, locals: Locals, directives: any): void {} + + dehydrate(): void {} + callOnAllChangesDone(): void {} _detectChangesInLightDomChildren(throwOnChange: boolean): void { diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.ts b/modules/angular2/src/change_detection/change_detection_jit_generator.ts index 01b02c2097..c6ff629935 100644 --- a/modules/angular2/src/change_detection/change_detection_jit_generator.ts +++ b/modules/angular2/src/change_detection/change_detection_jit_generator.ts @@ -38,7 +38,7 @@ export class ChangeDetectorJITGenerator { _fieldNames: List; _pipeNames: List; - constructor(public typeName: string, public changeDetectionStrategy: string, + constructor(public id: string, public changeDetectionStrategy: string, public records: List, public directiveRecords: List) { this._localNames = this._getLocalNames(records); this._changeNames = this._getChangeNames(this._localNames); @@ -48,10 +48,7 @@ export class ChangeDetectorJITGenerator { _getLocalNames(records: List): List { var index = 0; - var names = records.map((r) => { - var sanitizedName = r.name.replace(new RegExp("\\W", "g"), ''); - return `${sanitizedName}${index++}` - }); + var names = records.map((r) => { return _sanitizeName(`${r.name}${index++}`); }); return ["context"].concat(names); } @@ -68,9 +65,10 @@ export class ChangeDetectorJITGenerator { } generate(): Function { + var typeName = _sanitizeName(`ChangeDetector_${this.id}`); var classDefinition = ` - var ${this.typeName} = function ${this.typeName}(dispatcher, pipeRegistry, protos, directiveRecords) { - ${ABSTRACT_CHANGE_DETECTOR}.call(this); + var ${typeName} = function ${typeName}(dispatcher, pipeRegistry, protos, directiveRecords) { + ${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)}); ${DISPATCHER_ACCESSOR} = dispatcher; ${PIPE_REGISTRY_ACCESSOR} = pipeRegistry; ${PROTOS_ACCESSOR} = protos; @@ -80,9 +78,9 @@ export class ChangeDetectorJITGenerator { ${this._genFieldDefinitions()} } - ${this.typeName}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype); + ${typeName}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype); - ${this.typeName}.prototype.detectChangesInRecords = function(throwOnChange) { + ${typeName}.prototype.detectChangesInRecords = function(throwOnChange) { if (!this.hydrated()) { ${UTIL}.throwDehydrated(); } @@ -99,11 +97,11 @@ export class ChangeDetectorJITGenerator { ${ALREADY_CHECKED_ACCESSOR} = true; } - ${this.typeName}.prototype.callOnAllChangesDone = function() { + ${typeName}.prototype.callOnAllChangesDone = function() { ${this._genCallOnAllChangesDoneBody()} } - ${this.typeName}.prototype.hydrate = function(context, locals, directives) { + ${typeName}.prototype.hydrate = function(context, locals, directives) { ${MODE_ACCESSOR} = "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}"; ${CONTEXT_ACCESSOR} = context; ${LOCALS_ACCESSOR} = locals; @@ -112,21 +110,20 @@ export class ChangeDetectorJITGenerator { ${ALREADY_CHECKED_ACCESSOR} = false; } - ${this.typeName}.prototype.dehydrate = function() { + ${typeName}.prototype.dehydrate = function() { ${this._genPipeOnDestroy()} ${this._genFieldDefinitions()} ${LOCALS_ACCESSOR} = null; } - ${this.typeName}.prototype.hydrated = function() { + ${typeName}.prototype.hydrated = function() { return ${CONTEXT_ACCESSOR} !== null; } return function(dispatcher, pipeRegistry) { - return new ${this.typeName}(dispatcher, pipeRegistry, protos, directiveRecords); + return new ${typeName}(dispatcher, pipeRegistry, protos, directiveRecords); } `; - return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', 'directiveRecords', classDefinition)( AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords); @@ -444,3 +441,7 @@ export class ChangeDetectorJITGenerator { return retVal; } } + +function _sanitizeName(s: string): string { + return s.replace(new RegExp("\\W", "g"), ''); +} diff --git a/modules/angular2/src/change_detection/dynamic_change_detector.ts b/modules/angular2/src/change_detection/dynamic_change_detector.ts index 58a4178ca1..214f398201 100644 --- a/modules/angular2/src/change_detection/dynamic_change_detector.ts +++ b/modules/angular2/src/change_detection/dynamic_change_detector.ts @@ -21,10 +21,10 @@ export class DynamicChangeDetector extends AbstractChangeDetector { directives: any = null; alreadyChecked: boolean = false; - constructor(private changeControlStrategy: string, private dispatcher: any, + constructor(id: string, private changeControlStrategy: string, private dispatcher: any, private pipeRegistry: PipeRegistry, private protos: List, private directiveRecords: List) { - super(); + super(id); this.values = ListWrapper.createFixedSize(protos.length + 1); this.pipes = ListWrapper.createFixedSize(protos.length + 1); this.prevContexts = ListWrapper.createFixedSize(protos.length + 1); diff --git a/modules/angular2/src/change_detection/interfaces.ts b/modules/angular2/src/change_detection/interfaces.ts index bc78fcefd5..99e08d7fb2 100644 --- a/modules/angular2/src/change_detection/interfaces.ts +++ b/modules/angular2/src/change_detection/interfaces.ts @@ -3,10 +3,6 @@ import {Locals} from './parser/locals'; import {BindingRecord} from './binding_record'; import {DirectiveRecord} from './directive_record'; -export class ProtoChangeDetector { - instantiate(dispatcher: any): ChangeDetector { return null; } -} - /** * Interface used by Angular to control the change detection strategy for an application. * @@ -39,27 +35,30 @@ export class ChangeDetection { } } -export class ChangeDispatcher { - notifyOnBinding(bindingRecord: BindingRecord, value: any) {} +export interface ChangeDispatcher { + notifyOnBinding(bindingRecord: BindingRecord, value: any): void; + notifyOnAllChangesDone(): void; } -export class ChangeDetector { +export interface ChangeDetector { parent: ChangeDetector; mode: string; - addChild(cd: ChangeDetector): void {} - addShadowDomChild(cd: ChangeDetector): void {} - removeChild(cd: ChangeDetector): void {} - removeShadowDomChild(cd: ChangeDetector): void {} - remove(): void {} - hydrate(context: any, locals: Locals, directives: any): void {} - dehydrate(): void {} - markPathToRootAsCheckOnce(): void {} + addChild(cd: ChangeDetector): void; + addShadowDomChild(cd: ChangeDetector): void; + removeChild(cd: ChangeDetector): void; + removeShadowDomChild(cd: ChangeDetector): void; + remove(): void; + hydrate(context: any, locals: Locals, directives: any): void; + dehydrate(): void; + markPathToRootAsCheckOnce(): void; - detectChanges(): void {} - checkNoChanges(): void {} + detectChanges(): void; + checkNoChanges(): void; } +export interface ProtoChangeDetector { instantiate(dispatcher: any): ChangeDetector; } + export class ChangeDetectorDefinition { constructor(public id: string, public strategy: string, public variableNames: List, public bindingRecords: List, diff --git a/modules/angular2/src/change_detection/jit_proto_change_detector.ts b/modules/angular2/src/change_detection/jit_proto_change_detector.ts index f808c94d39..4672e53139 100644 --- a/modules/angular2/src/change_detection/jit_proto_change_detector.ts +++ b/modules/angular2/src/change_detection/jit_proto_change_detector.ts @@ -6,12 +6,10 @@ import {ChangeDetectorJITGenerator} from './change_detection_jit_generator'; import {coalesce} from './coalesce'; import {ProtoRecordBuilder} from './proto_change_detector'; -var _jitProtoChangeDetectorClassCounter: number = 0; -export class JitProtoChangeDetector extends ProtoChangeDetector { +export class JitProtoChangeDetector implements ProtoChangeDetector { _factory: Function; constructor(private _pipeRegistry, private definition: ChangeDetectorDefinition) { - super(); this._factory = this._createFactory(definition); } @@ -25,10 +23,8 @@ export class JitProtoChangeDetector extends ProtoChangeDetector { var recordBuilder = new ProtoRecordBuilder(); ListWrapper.forEach(definition.bindingRecords, (b) => { recordBuilder.add(b, definition.variableNames); }); - var c = _jitProtoChangeDetectorClassCounter++; var records = coalesce(recordBuilder.records); - var typeName = `ChangeDetector${c}`; - return new ChangeDetectorJITGenerator(typeName, definition.strategy, records, + return new ChangeDetectorJITGenerator(definition.id, definition.strategy, records, this.definition.directiveRecords) .generate(); } diff --git a/modules/angular2/src/change_detection/pregen_proto_change_detector.ts b/modules/angular2/src/change_detection/pregen_proto_change_detector.ts index e0020733c8..52df89cb02 100644 --- a/modules/angular2/src/change_detection/pregen_proto_change_detector.ts +++ b/modules/angular2/src/change_detection/pregen_proto_change_detector.ts @@ -5,7 +5,7 @@ import {coalesce} from './coalesce'; export {Function as PregenProtoChangeDetectorFactory}; -export class PregenProtoChangeDetector extends ProtoChangeDetector { +export class PregenProtoChangeDetector implements ProtoChangeDetector { static isSupported(): boolean { return false; } instantiate(dispatcher: any): ChangeDetector { diff --git a/modules/angular2/src/change_detection/proto_change_detector.ts b/modules/angular2/src/change_detection/proto_change_detector.ts index 3bae1b84cf..a06e00a1ba 100644 --- a/modules/angular2/src/change_detection/proto_change_detector.ts +++ b/modules/angular2/src/change_detection/proto_change_detector.ts @@ -25,12 +25,7 @@ import { SafeMethodCall } from './parser/ast'; -import { - ChangeDispatcher, - ChangeDetector, - ProtoChangeDetector, - ChangeDetectorDefinition -} from './interfaces'; +import {ChangeDetector, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces'; import {ChangeDetectionUtil} from './change_detection_util'; import {DynamicChangeDetector} from './dynamic_change_detector'; import {PipeRegistry} from './pipes/pipe_registry'; @@ -41,17 +36,17 @@ import {coalesce} from './coalesce'; import {ProtoRecord, RecordType} from './proto_record'; -export class DynamicProtoChangeDetector extends ProtoChangeDetector { +export class DynamicProtoChangeDetector implements ProtoChangeDetector { _records: List; constructor(private _pipeRegistry: PipeRegistry, private definition: ChangeDetectorDefinition) { - super(); this._records = this._createRecords(definition); } instantiate(dispatcher: any) { - return new DynamicChangeDetector(this.definition.strategy, dispatcher, this._pipeRegistry, - this._records, this.definition.directiveRecords); + return new DynamicChangeDetector(this.definition.id, this.definition.strategy, dispatcher, + this._pipeRegistry, this._records, + this.definition.directiveRecords); } _createRecords(definition: ChangeDetectorDefinition) { diff --git a/modules/angular2/src/test_lib/spies.ts b/modules/angular2/src/test_lib/spies.ts new file mode 100644 index 0000000000..cbff71a2d4 --- /dev/null +++ b/modules/angular2/src/test_lib/spies.ts @@ -0,0 +1,47 @@ +import { + ChangeDetector, + ProtoChangeDetector, + DynamicChangeDetector +} from 'angular2/change_detection'; +import {SpyObject, proxy} from './test_lib'; + +// Remove dummy methods after https://github.com/angular/ts2dart/issues/209 is fixed. +@proxy +export class SpyChangeDetector extends SpyObject implements ChangeDetector { + parent: ChangeDetector; + mode: string; + + constructor() { super(DynamicChangeDetector, true); } + + addChild(cd: ChangeDetector): void { return this.spy("addChild")(cd); } + + addShadowDomChild(cd: ChangeDetector): void { return this.spy("addShadowDomChild")(cd); } + + removeChild(cd: ChangeDetector): void { return this.spy("removeChild")(cd); } + + removeShadowDomChild(cd: ChangeDetector): void { return this.spy("removeShadowDomChild")(cd); } + + remove(): void { return this.spy("remove")(); } + + hydrate(context: any, locals: any, directives: any): void { + return this.spy("hydrate")(context, locals, directives); + } + + dehydrate(): void { return this.spy("dehydrate")(); } + + markPathToRootAsCheckOnce(): void { return this.spy("markPathToRootAsCheckOnce")(); } + + detectChanges(): void { return this.spy("detectChanges")(); } + + checkNoChanges(): void { return this.spy("checkNoChanges")(); } + + noSuchMethod(m) { return super.noSuchMethod(m) } +} + +// Remove dummy methods after https://github.com/angular/ts2dart/issues/209 is fixed. +@proxy +export class SpyProtoChangeDetector extends SpyObject implements ProtoChangeDetector { + constructor() { super(DynamicChangeDetector, true); } + + instantiate(v: any): any { return this.spy("instantiate")(v); } +} \ No newline at end of file diff --git a/modules/angular2/src/test_lib/test_lib.dart b/modules/angular2/src/test_lib/test_lib.dart index 9ff6092f72..aac0a380e9 100644 --- a/modules/angular2/src/test_lib/test_lib.dart +++ b/modules/angular2/src/test_lib/test_lib.dart @@ -187,7 +187,7 @@ class SpyFunction extends gns.SpyFunction { class SpyObject extends gns.SpyObject { final Map _spyFuncs = {}; - SpyObject([arg]) {} + SpyObject([arg, arg2]) {} SpyFunction spy(String funcName) => _spyFuncs.putIfAbsent(funcName, () => new SpyFunction(funcName)); diff --git a/modules/angular2/src/test_lib/test_lib.ts b/modules/angular2/src/test_lib/test_lib.ts index 651527a0a2..dcb4e22398 100644 --- a/modules/angular2/src/test_lib/test_lib.ts +++ b/modules/angular2/src/test_lib/test_lib.ts @@ -280,7 +280,7 @@ export interface GuinessCompatibleSpy extends jasmine.Spy { } export class SpyObject { - constructor(type = null) { + constructor(type = null, forceSpyCreation: boolean = false) { if (type) { for (var prop in type.prototype) { var m = null; @@ -293,7 +293,11 @@ export class SpyObject { // should not matter. } if (typeof m === 'function') { - this.spy(prop); + if (forceSpyCreation) { + this.createSpy(prop); + } else { + this.spy(prop); + } } } } @@ -303,8 +307,14 @@ export class SpyObject { spy(name) { if (!this[name]) { - this[name] = this._createGuinnessCompatibleSpy(name); + return this.createSpy(name); + } else { + return this[name]; } + } + + createSpy(name) { + this[name] = this._createGuinnessCompatibleSpy(name); return this[name]; } diff --git a/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart b/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart index c2ba2ffa2d..a205bc4449 100644 --- a/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart +++ b/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart @@ -142,7 +142,7 @@ class _CodegenState { this.$_DISPATCHER_ACCESSOR, this.$_PIPE_REGISTRY_ACCESSOR, this.$_PROTOS_ACCESSOR, - this.$_DIRECTIVES_ACCESSOR) : super(); + this.$_DIRECTIVES_ACCESSOR) : super(${JSON.encode(_changeDetectorDefId)}); void detectChangesInRecords(throwOnChange) { if (!hydrated()) { diff --git a/modules/angular2/test/change_detection/change_detection_spec.ts b/modules/angular2/test/change_detection/change_detection_spec.ts index f908b99137..809a700881 100644 --- a/modules/angular2/test/change_detection/change_detection_spec.ts +++ b/modules/angular2/test/change_detection/change_detection_spec.ts @@ -1,21 +1,28 @@ -import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib'; +import { + ddescribe, + describe, + it, + iit, + xit, + expect, + beforeEach, + afterEach, + SpyProtoChangeDetector +} from 'angular2/test_lib'; import { PreGeneratedChangeDetection, ChangeDetectorDefinition, - ProtoChangeDetector, DynamicProtoChangeDetector } from 'angular2/change_detection'; -class DummyChangeDetector extends ProtoChangeDetector {} - export function main() { describe("PreGeneratedChangeDetection", () => { var proto; var def; beforeEach(() => { - proto = new DummyChangeDetector(); + proto = new SpyProtoChangeDetector(); def = new ChangeDetectorDefinition('id', null, [], [], []); }); diff --git a/modules/angular2/test/change_detection/change_detector_spec.ts b/modules/angular2/test/change_detection/change_detector_spec.ts index 84d027dab1..29a43ecbac 100644 --- a/modules/angular2/test/change_detection/change_detector_spec.ts +++ b/modules/angular2/test/change_detection/change_detector_spec.ts @@ -990,15 +990,12 @@ class FakeDirectives { getDetectorFor(di: DirectiveIndex) { return this.detectors[di.directiveIndex]; } } -class TestDispatcher extends ChangeDispatcher { +class TestDispatcher implements ChangeDispatcher { log: List; loggedValues: List; onAllChangesDoneCalled: boolean = false; - constructor() { - super(); - this.clear(); - } + constructor() { this.clear(); } clear() { this.log = []; diff --git a/modules/angular2/test/core/compiler/element_injector_spec.ts b/modules/angular2/test/core/compiler/element_injector_spec.ts index 2871ec2c46..60d742c75d 100644 --- a/modules/angular2/test/core/compiler/element_injector_spec.ts +++ b/modules/angular2/test/core/compiler/element_injector_spec.ts @@ -911,7 +911,7 @@ export function main() { }); it('should inject ChangeDetectorRef', () => { - var cd = new DynamicChangeDetector(null, null, null, [], []); + var cd = new DynamicChangeDetector(null, null, null, null, [], []); var view = new DummyView(); var childView = new DummyView(); childView.changeDetector = cd; diff --git a/modules/angular2/test/core/compiler/view_manager_utils_spec.ts b/modules/angular2/test/core/compiler/view_manager_utils_spec.ts index c5c99d0fbe..ec74c4ff48 100644 --- a/modules/angular2/test/core/compiler/view_manager_utils_spec.ts +++ b/modules/angular2/test/core/compiler/view_manager_utils_spec.ts @@ -13,6 +13,7 @@ import { it, xit, SpyObject, + SpyChangeDetector, proxy, Log } from 'angular2/test_lib'; @@ -22,7 +23,6 @@ import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang'; import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; -import {ChangeDetector} from 'angular2/change_detection'; import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; import { DirectiveBinding, @@ -279,13 +279,6 @@ class SpyElementInjector extends SpyObject { noSuchMethod(m) { return super.noSuchMethod(m) } } -@proxy -@IMPLEMENTS(ChangeDetector) -class SpyChangeDetector extends SpyObject { - constructor() { super(ChangeDetector); } - noSuchMethod(m) { return super.noSuchMethod(m) } -} - @proxy @IMPLEMENTS(PreBuiltObjects) class SpyPreBuiltObjects extends SpyObject { diff --git a/modules/angular2/test/core/life_cycle/life_cycle_spec.ts b/modules/angular2/test/core/life_cycle/life_cycle_spec.ts index 6727dd06c5..4774371b5d 100644 --- a/modules/angular2/test/core/life_cycle/life_cycle_spec.ts +++ b/modules/angular2/test/core/life_cycle/life_cycle_spec.ts @@ -11,26 +11,18 @@ import { AsyncTestCompleter, fakeAsync, tick, - SpyObject, inject, - proxy + SpyChangeDetector, } from 'angular2/test_lib'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; -import {ChangeDetector} from 'angular2/change_detection'; import {IMPLEMENTS} from 'angular2/src/facade/lang'; -@proxy -@IMPLEMENTS(ChangeDetector) -class SpyChangeDetector extends SpyObject { - constructor() { super(ChangeDetector); } - noSuchMethod(m) { return super.noSuchMethod(m) } -} - export function main() { describe("LifeCycle", () => { it("should throw when reentering tick", () => { var cd = new SpyChangeDetector(); var lc = new LifeCycle(null, cd, false); + cd.spy("detectChanges").andCallFake(() => lc.tick()); expect(() => lc.tick()).toThrowError("LifeCycle.tick is called recursively"); }); diff --git a/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart index 5e7a8bc166..6682e577f3 100644 --- a/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart +++ b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart @@ -34,7 +34,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector { _MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry, this._protos, this._directiveRecords) - : super(); + : super("MyComponent_comp_0"); void detectChangesInRecords(throwOnChange) { if (!hydrated()) { diff --git a/modules/angular2/test_lib.ts b/modules/angular2/test_lib.ts index 99c3f3f066..ffc3f5251a 100644 --- a/modules/angular2/test_lib.ts +++ b/modules/angular2/test_lib.ts @@ -1,4 +1,5 @@ export * from './src/test_lib/test_lib'; +export * from './src/test_lib/spies'; export * from './src/test_lib/utils'; export * from './src/test_lib/fake_async'; export * from './src/test_lib/test_component_builder'; diff --git a/modules/benchmarks/src/change_detection/change_detection_benchmark.ts b/modules/benchmarks/src/change_detection/change_detection_benchmark.ts index f0864a65b6..a2ed516439 100644 --- a/modules/benchmarks/src/change_detection/change_detection_benchmark.ts +++ b/modules/benchmarks/src/change_detection/change_detection_benchmark.ts @@ -379,7 +379,7 @@ class FakeDirectives { getDirectiveFor(record) { return this.targetObj; } } -class DummyDispatcher extends ChangeDispatcher { +class DummyDispatcher implements ChangeDispatcher { notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; } notifyOnAllChangesDone() {} }