fix(upgrade): Update types for TypeScript nullability support

Closes #15897
This commit is contained in:
Miško Hevery 2017-03-24 09:59:18 -07:00 committed by Tobias Bosch
parent a0d124bd91
commit 01d93f3af8
14 changed files with 134 additions and 129 deletions

View File

@ -84,7 +84,7 @@ export function downgradeComponent(info: {
const componentFactoryResolver: ComponentFactoryResolver = const componentFactoryResolver: ComponentFactoryResolver =
injector.get(ComponentFactoryResolver); injector.get(ComponentFactoryResolver);
const componentFactory: ComponentFactory<any> = const componentFactory: ComponentFactory<any> =
componentFactoryResolver.resolveComponentFactory(info.component); componentFactoryResolver.resolveComponentFactory(info.component) !;
if (!componentFactory) { if (!componentFactory) {
throw new Error('Expecting ComponentFactory for: ' + getComponentName(info.component)); throw new Error('Expecting ComponentFactory for: ' + getComponentName(info.component));
@ -130,7 +130,7 @@ class ParentInjectorPromise {
constructor(private element: angular.IAugmentedJQuery) { constructor(private element: angular.IAugmentedJQuery) {
// Store the promise on the element. // Store the promise on the element.
element.data(this.injectorKey, this); element.data !(this.injectorKey, this);
} }
then(callback: (injector: Injector) => any) { then(callback: (injector: Injector) => any) {
@ -145,10 +145,10 @@ class ParentInjectorPromise {
this.injector = injector; this.injector = injector;
// Store the real injector on the element. // Store the real injector on the element.
this.element.data(this.injectorKey, injector); this.element.data !(this.injectorKey, injector);
// Release the element to prevent memory leaks. // Release the element to prevent memory leaks.
this.element = null; this.element = null !;
// Run the queued callbacks. // Run the queued callbacks.
this.callbacks.forEach(callback => callback(injector)); this.callbacks.forEach(callback => callback(injector));

View File

@ -19,11 +19,11 @@ const INITIAL_VALUE = {
export class DowngradeComponentAdapter { export class DowngradeComponentAdapter {
private inputChangeCount: number = 0; private inputChangeCount: number = 0;
private inputChanges: SimpleChanges = null; private inputChanges: SimpleChanges|null = null;
private componentScope: angular.IScope; private componentScope: angular.IScope;
private componentRef: ComponentRef<any> = null; private componentRef: ComponentRef<any>|null = null;
private component: any = null; private component: any = null;
private changeDetector: ChangeDetectorRef = null; private changeDetector: ChangeDetectorRef|null = null;
constructor( constructor(
private id: string, private element: angular.IAugmentedJQuery, private id: string, private element: angular.IAugmentedJQuery,
@ -40,12 +40,12 @@ export class DowngradeComponentAdapter {
const projectableNodes: Node[][] = this.groupProjectableNodes(); const projectableNodes: Node[][] = this.groupProjectableNodes();
const linkFns = projectableNodes.map(nodes => this.$compile(nodes)); const linkFns = projectableNodes.map(nodes => this.$compile(nodes));
this.element.empty(); this.element.empty !();
linkFns.forEach(linkFn => { linkFns.forEach(linkFn => {
linkFn(this.scope, (clone: Node[]) => { linkFn(this.scope, (clone: Node[]) => {
compiledProjectableNodes.push(clone); compiledProjectableNodes.push(clone);
this.element.append(clone); this.element.append !(clone);
}); });
}); });
@ -109,7 +109,7 @@ export class DowngradeComponentAdapter {
this.componentScope.$watch(() => this.inputChangeCount, () => { this.componentScope.$watch(() => this.inputChangeCount, () => {
const inputChanges = this.inputChanges; const inputChanges = this.inputChanges;
this.inputChanges = {}; this.inputChanges = {};
(<OnChanges>this.component).ngOnChanges(inputChanges); (<OnChanges>this.component).ngOnChanges(inputChanges !);
}); });
} }
this.componentScope.$watch(() => this.changeDetector && this.changeDetector.detectChanges()); this.componentScope.$watch(() => this.changeDetector && this.changeDetector.detectChanges());
@ -133,11 +133,11 @@ export class DowngradeComponentAdapter {
expr = (attrs as any /** TODO #9100 */)[output.onAttr]; expr = (attrs as any /** TODO #9100 */)[output.onAttr];
} else if (attrs.hasOwnProperty(output.parenAttr)) { } else if (attrs.hasOwnProperty(output.parenAttr)) {
expr = (attrs as any /** TODO #9100 */)[output.parenAttr]; expr = (attrs as any /** TODO #9100 */)[output.parenAttr];
} else if (attrs.hasOwnProperty(bindonAttr)) { } else if (attrs.hasOwnProperty(bindonAttr !)) {
expr = (attrs as any /** TODO #9100 */)[bindonAttr]; expr = (attrs as any /** TODO #9100 */)[bindonAttr !];
assignExpr = true; assignExpr = true;
} else if (attrs.hasOwnProperty(bracketParenAttr)) { } else if (attrs.hasOwnProperty(bracketParenAttr !)) {
expr = (attrs as any /** TODO #9100 */)[bracketParenAttr]; expr = (attrs as any /** TODO #9100 */)[bracketParenAttr !];
assignExpr = true; assignExpr = true;
} }
@ -164,13 +164,13 @@ export class DowngradeComponentAdapter {
} }
registerCleanup() { registerCleanup() {
this.element.bind('$destroy', () => { this.element.bind !('$destroy', () => {
this.componentScope.$destroy(); this.componentScope.$destroy();
this.componentRef.destroy(); this.componentRef !.destroy();
}); });
} }
getInjector(): Injector { return this.componentRef && this.componentRef.injector; } getInjector(): Injector { return this.componentRef ! && this.componentRef !.injector; }
private updateInput(prop: string, prevValue: any, currValue: any) { private updateInput(prop: string, prevValue: any, currValue: any) {
if (this.inputChanges) { if (this.inputChanges) {
@ -183,7 +183,7 @@ export class DowngradeComponentAdapter {
groupProjectableNodes() { groupProjectableNodes() {
let ngContentSelectors = this.componentFactory.ngContentSelectors; let ngContentSelectors = this.componentFactory.ngContentSelectors;
return groupNodesBySelector(ngContentSelectors, this.element.contents()); return groupNodesBySelector(ngContentSelectors, this.element.contents !());
} }
} }
@ -209,9 +209,9 @@ export function groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]
return projectableNodes; return projectableNodes;
} }
function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number { function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number|null {
const ngContentIndices: number[] = []; const ngContentIndices: number[] = [];
let wildcardNgContentIndex: number; let wildcardNgContentIndex: number = -1;
for (let i = 0; i < ngContentSelectors.length; i++) { for (let i = 0; i < ngContentSelectors.length; i++) {
const selector = ngContentSelectors[i]; const selector = ngContentSelectors[i];
if (selector === '*') { if (selector === '*') {
@ -224,7 +224,7 @@ function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]):
} }
ngContentIndices.sort(); ngContentIndices.sort();
if (wildcardNgContentIndex !== undefined) { if (wildcardNgContentIndex !== -1) {
ngContentIndices.push(wildcardNgContentIndex); ngContentIndices.push(wildcardNgContentIndex);
} }
return ngContentIndices.length ? ngContentIndices[0] : null; return ngContentIndices.length ? ngContentIndices[0] : null;

View File

@ -26,12 +26,12 @@ export function controllerKey(name: string): string {
export function getAttributesAsArray(node: Node): [string, string][] { export function getAttributesAsArray(node: Node): [string, string][] {
const attributes = node.attributes; const attributes = node.attributes;
let asArray: [string, string][]; let asArray: [string, string][] = undefined !;
if (attributes) { if (attributes) {
let attrLen = attributes.length; let attrLen = attributes.length;
asArray = new Array(attrLen); asArray = new Array(attrLen);
for (let i = 0; i < attrLen; i++) { for (let i = 0; i < attrLen; i++) {
asArray[i] = [attributes[i].nodeName, attributes[i].nodeValue]; asArray[i] = [attributes[i].nodeName, attributes[i].nodeValue !];
} }
} }
return asArray || []; return asArray || [];

View File

@ -113,7 +113,7 @@ export class UpgradeAdapter {
private upgradedProviders: Provider[] = []; private upgradedProviders: Provider[] = [];
private ngZone: NgZone; private ngZone: NgZone;
private ng1Module: angular.IModule; private ng1Module: angular.IModule;
private moduleRef: NgModuleRef<any> = null; private moduleRef: NgModuleRef<any>|null = null;
private ng2BootstrapDeferred: Deferred<angular.IInjectorService>; private ng2BootstrapDeferred: Deferred<angular.IInjectorService>;
constructor(private ng2AppModule: Type<any>, private compilerOptions?: CompilerOptions) { constructor(private ng2AppModule: Type<any>, private compilerOptions?: CompilerOptions) {
@ -382,7 +382,7 @@ export class UpgradeAdapter {
const windowAngular = (window as any /** TODO #???? */)['angular']; const windowAngular = (window as any /** TODO #???? */)['angular'];
windowAngular.resumeBootstrap = undefined; windowAngular.resumeBootstrap = undefined;
this.ngZone.run(() => { angular.bootstrap(element, [this.ng1Module.name], config); }); this.ngZone.run(() => { angular.bootstrap(element, [this.ng1Module.name], config !); });
const ng1BootstrapPromise = new Promise((resolve) => { const ng1BootstrapPromise = new Promise((resolve) => {
if (windowAngular.resumeBootstrap) { if (windowAngular.resumeBootstrap) {
const originalResumeBootstrap: () => void = windowAngular.resumeBootstrap; const originalResumeBootstrap: () => void = windowAngular.resumeBootstrap;
@ -397,8 +397,8 @@ export class UpgradeAdapter {
}); });
Promise.all([this.ng2BootstrapDeferred.promise, ng1BootstrapPromise]).then(([ng1Injector]) => { Promise.all([this.ng2BootstrapDeferred.promise, ng1BootstrapPromise]).then(([ng1Injector]) => {
angular.element(element).data(controllerKey(INJECTOR_KEY), this.moduleRef.injector); angular.element(element).data !(controllerKey(INJECTOR_KEY), this.moduleRef !.injector);
this.moduleRef.injector.get(NgZone).run( this.moduleRef !.injector.get(NgZone).run(
() => { (<any>upgrade)._bootstrapDone(this.moduleRef, ng1Injector); }); () => { (<any>upgrade)._bootstrapDone(this.moduleRef, ng1Injector); });
}, onError); }, onError);
return upgrade; return upgrade;
@ -494,9 +494,9 @@ export class UpgradeAdapter {
this.ngZone = new NgZone({enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec')}); this.ngZone = new NgZone({enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec')});
this.ng2BootstrapDeferred = new Deferred(); this.ng2BootstrapDeferred = new Deferred();
ng1Module.factory(INJECTOR_KEY, () => this.moduleRef.injector.get(Injector)) ng1Module.factory(INJECTOR_KEY, () => this.moduleRef !.injector.get(Injector))
.constant(NG_ZONE_KEY, this.ngZone) .constant(NG_ZONE_KEY, this.ngZone)
.factory(COMPILER_KEY, () => this.moduleRef.injector.get(Compiler)) .factory(COMPILER_KEY, () => this.moduleRef !.injector.get(Compiler))
.config([ .config([
'$provide', '$injector', '$provide', '$injector',
(provide: angular.IProvideService, ng1Injector: angular.IInjectorService) => { (provide: angular.IProvideService, ng1Injector: angular.IInjectorService) => {
@ -524,7 +524,7 @@ export class UpgradeAdapter {
const newWhenStable = function(callback: Function) { const newWhenStable = function(callback: Function) {
originalWhenStable.call(this, function() { originalWhenStable.call(this, function() {
const ng2Testability: Testability = const ng2Testability: Testability =
upgradeAdapter.moduleRef.injector.get(Testability); upgradeAdapter.moduleRef !.injector.get(Testability);
if (ng2Testability.isStable()) { if (ng2Testability.isStable()) {
callback.apply(this, arguments); callback.apply(this, arguments);
} else { } else {
@ -601,7 +601,7 @@ class ParentInjectorPromise {
constructor(private element: angular.IAugmentedJQuery) { constructor(private element: angular.IAugmentedJQuery) {
// store the promise on the element // store the promise on the element
element.data(controllerKey(INJECTOR_KEY), this); element.data !(controllerKey(INJECTOR_KEY), this);
} }
then(callback: (injector: Injector) => any) { then(callback: (injector: Injector) => any) {
@ -616,10 +616,10 @@ class ParentInjectorPromise {
this.injector = injector; this.injector = injector;
// reset the element data to point to the real injector // reset the element data to point to the real injector
this.element.data(controllerKey(INJECTOR_KEY), injector); this.element.data !(controllerKey(INJECTOR_KEY), injector);
// clean out the element to prevent memory leaks // clean out the element to prevent memory leaks
this.element = null; this.element = null !;
// run all the queued callbacks // run all the queued callbacks
this.callbacks.forEach((callback) => callback(injector)); this.callbacks.forEach((callback) => callback(injector));
@ -635,12 +635,12 @@ class ParentInjectorPromise {
*/ */
export class UpgradeAdapterRef { export class UpgradeAdapterRef {
/* @internal */ /* @internal */
private _readyFn: (upgradeAdapterRef?: UpgradeAdapterRef) => void = null; private _readyFn: ((upgradeAdapterRef?: UpgradeAdapterRef) => void)|null = null;
public ng1RootScope: angular.IRootScopeService = null; public ng1RootScope: angular.IRootScopeService = null !;
public ng1Injector: angular.IInjectorService = null; public ng1Injector: angular.IInjectorService = null !;
public ng2ModuleRef: NgModuleRef<any> = null; public ng2ModuleRef: NgModuleRef<any> = null !;
public ng2Injector: Injector = null; public ng2Injector: Injector = null !;
/* @internal */ /* @internal */
private _bootstrapDone(ngModuleRef: NgModuleRef<any>, ng1Injector: angular.IInjectorService) { private _bootstrapDone(ngModuleRef: NgModuleRef<any>, ng1Injector: angular.IInjectorService) {
@ -658,13 +658,13 @@ export class UpgradeAdapterRef {
* The `ready` callback function is invoked inside the Angular zone, therefore it does not * The `ready` callback function is invoked inside the Angular zone, therefore it does not
* require a call to `$apply()`. * require a call to `$apply()`.
*/ */
public ready(fn: (upgradeAdapterRef?: UpgradeAdapterRef) => void) { this._readyFn = fn; } public ready(fn: (upgradeAdapterRef: UpgradeAdapterRef) => void) { this._readyFn = fn; }
/** /**
* Dispose of running hybrid AngularJS / Angular application. * Dispose of running hybrid AngularJS / Angular application.
*/ */
public dispose() { public dispose() {
this.ng1Injector.get($ROOT_SCOPE).$destroy(); this.ng1Injector !.get($ROOT_SCOPE).$destroy();
this.ng2ModuleRef.destroy(); this.ng2ModuleRef !.destroy();
} }
} }

View File

@ -44,30 +44,32 @@ export class UpgradeNg1ComponentAdapterBuilder {
propertyOutputs: string[] = []; propertyOutputs: string[] = [];
checkProperties: string[] = []; checkProperties: string[] = [];
propertyMap: {[name: string]: string} = {}; propertyMap: {[name: string]: string} = {};
linkFn: angular.ILinkFn = null; linkFn: angular.ILinkFn|null = null;
directive: angular.IDirective = null; directive: angular.IDirective|null = null;
$controller: angular.IControllerService = null; $controller: angular.IControllerService|null = null;
constructor(public name: string) { constructor(public name: string) {
const selector = name.replace( const selector = name.replace(
CAMEL_CASE, (all: any /** TODO #9100 */, next: string) => '-' + next.toLowerCase()); CAMEL_CASE, (all: any /** TODO #9100 */, next: string) => '-' + next.toLowerCase());
const self = this; const self = this;
this.type = this.type = Directive({
Directive({selector: selector, inputs: this.inputsRename, outputs: this.outputsRename}) selector: selector,
.Class({ inputs: this.inputsRename,
constructor: [ outputs: this.outputsRename
new Inject($SCOPE), ElementRef, }).Class({
function(scope: angular.IScope, elementRef: ElementRef) { constructor: [
return new UpgradeNg1ComponentAdapter( new Inject($SCOPE), ElementRef,
self.linkFn, scope, self.directive, elementRef, self.$controller, self.inputs, function(scope: angular.IScope, elementRef: ElementRef) {
self.outputs, self.propertyOutputs, self.checkProperties, self.propertyMap); return new UpgradeNg1ComponentAdapter(
} self.linkFn !, scope, self.directive !, elementRef, self.$controller !, self.inputs,
], self.outputs, self.propertyOutputs, self.checkProperties, self.propertyMap);
ngOnInit: function() { /* needs to be here for ng2 to properly detect it */ }, }
ngOnChanges: function() { /* needs to be here for ng2 to properly detect it */ }, ],
ngDoCheck: function() { /* needs to be here for ng2 to properly detect it */ }, ngOnInit: function() { /* needs to be here for ng2 to properly detect it */ },
ngOnDestroy: function() { /* needs to be here for ng2 to properly detect it */ }, ngOnChanges: function() { /* needs to be here for ng2 to properly detect it */ },
}); ngDoCheck: function() { /* needs to be here for ng2 to properly detect it */ },
ngOnDestroy: function() { /* needs to be here for ng2 to properly detect it */ },
});
} }
extractDirective(injector: angular.IInjectorService): angular.IDirective { extractDirective(injector: angular.IInjectorService): angular.IDirective {
@ -90,13 +92,13 @@ export class UpgradeNg1ComponentAdapterBuilder {
} }
extractBindings() { extractBindings() {
const btcIsObject = typeof this.directive.bindToController === 'object'; const btcIsObject = typeof this.directive !.bindToController === 'object';
if (btcIsObject && Object.keys(this.directive.scope).length) { if (btcIsObject && Object.keys(this.directive !.scope).length) {
throw new Error( throw new Error(
`Binding definitions on scope and controller at the same time are not supported.`); `Binding definitions on scope and controller at the same time are not supported.`);
} }
const context = (btcIsObject) ? this.directive.bindToController : this.directive.scope; const context = (btcIsObject) ? this.directive !.bindToController : this.directive !.scope;
if (typeof context == 'object') { if (typeof context == 'object') {
for (const name in context) { for (const name in context) {
@ -147,14 +149,15 @@ export class UpgradeNg1ComponentAdapterBuilder {
compileTemplate( compileTemplate(
compile: angular.ICompileService, templateCache: angular.ITemplateCacheService, compile: angular.ICompileService, templateCache: angular.ITemplateCacheService,
httpBackend: angular.IHttpBackendService): Promise<angular.ILinkFn> { httpBackend: angular.IHttpBackendService): Promise<angular.ILinkFn>|null {
if (this.directive.template !== undefined) { if (this.directive !.template !== undefined) {
this.linkFn = compileHtml( this.linkFn = compileHtml(
isFunction(this.directive.template) ? this.directive.template() : isFunction(this.directive !.template) ? (this.directive !.template as Function)() :
this.directive.template); this.directive !.template);
} else if (this.directive.templateUrl) { } else if (this.directive !.templateUrl) {
const url = isFunction(this.directive.templateUrl) ? this.directive.templateUrl() : const url = isFunction(this.directive !.templateUrl) ?
this.directive.templateUrl; (this.directive !.templateUrl as Function)() :
this.directive !.templateUrl;
const html = templateCache.get(url); const html = templateCache.get(url);
if (html !== undefined) { if (html !== undefined) {
this.linkFn = compileHtml(html); this.linkFn = compileHtml(html);
@ -200,7 +203,7 @@ export class UpgradeNg1ComponentAdapterBuilder {
exportedComponent.$controller = $controller; exportedComponent.$controller = $controller;
exportedComponent.extractBindings(); exportedComponent.extractBindings();
const promise: Promise<angular.ILinkFn> = const promise: Promise<angular.ILinkFn> =
exportedComponent.compileTemplate(compile, templateCache, httpBackend); exportedComponent.compileTemplate(compile, templateCache, httpBackend) !;
if (promise) promises.push(promise); if (promise) promises.push(promise);
} }
} }
@ -209,8 +212,8 @@ export class UpgradeNg1ComponentAdapterBuilder {
} }
class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck { class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
private controllerInstance: IControllerInstance = null; private controllerInstance: IControllerInstance|null = null;
destinationObj: IBindingDestination = null; destinationObj: IBindingDestination|null = null;
checkLastValues: any[] = []; checkLastValues: any[] = [];
componentScope: angular.IScope; componentScope: angular.IScope;
element: Element; element: Element;
@ -261,7 +264,7 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
if (link) { if (link) {
const attrs: angular.IAttributes = NOT_SUPPORTED; const attrs: angular.IAttributes = NOT_SUPPORTED;
const transcludeFn: angular.ITranscludeFunction = NOT_SUPPORTED; const transcludeFn: angular.ITranscludeFunction = NOT_SUPPORTED;
const linkController = this.resolveRequired(this.$element, this.directive.require); const linkController = this.resolveRequired(this.$element, this.directive.require !);
(<angular.IDirectiveLinkFn>this.directive.link)( (<angular.IDirectiveLinkFn>this.directive.link)(
this.componentScope, this.$element, attrs, linkController, transcludeFn); this.componentScope, this.$element, attrs, linkController, transcludeFn);
} }
@ -273,8 +276,8 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
childNodes.push(childNode); childNodes.push(childNode);
} }
this.linkFn(this.componentScope, (clonedElement, scope) => { this.linkFn(this.componentScope, (clonedElement, scope) => {
for (let i = 0, ii = clonedElement.length; i < ii; i++) { for (let i = 0, ii = clonedElement !.length; i < ii; i++) {
this.element.appendChild(clonedElement[i]); this.element.appendChild(clonedElement ![i]);
} }
}, { }, {
parentBoundTranscludeFn: (scope: any /** TODO #9100 */, parentBoundTranscludeFn: (scope: any /** TODO #9100 */,
@ -294,8 +297,8 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
ng1Changes[this.propertyMap[name]] = change; ng1Changes[this.propertyMap[name]] = change;
}); });
if (isFunction(this.destinationObj.$onChanges)) { if (isFunction(this.destinationObj !.$onChanges)) {
this.destinationObj.$onChanges(ng1Changes); this.destinationObj !.$onChanges !(ng1Changes);
} }
} }
@ -304,7 +307,7 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
const lastValues = this.checkLastValues; const lastValues = this.checkLastValues;
const checkProperties = this.checkProperties; const checkProperties = this.checkProperties;
for (let i = 0; i < checkProperties.length; i++) { for (let i = 0; i < checkProperties.length; i++) {
const value = destinationObj[checkProperties[i]]; const value = destinationObj ![checkProperties[i]];
const last = lastValues[i]; const last = lastValues[i];
if (value !== last) { if (value !== last) {
if (typeof value == 'number' && isNaN(value) && typeof last == 'number' && isNaN(last)) { if (typeof value == 'number' && isNaN(value) && typeof last == 'number' && isNaN(last)) {
@ -328,14 +331,14 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
} }
setComponentProperty(name: string, value: any) { setComponentProperty(name: string, value: any) {
this.destinationObj[this.propertyMap[name]] = value; this.destinationObj ![this.propertyMap[name]] = value;
} }
private buildController(controllerType: any /** TODO #9100 */) { private buildController(controllerType: any /** TODO #9100 */) {
const locals = {$scope: this.componentScope, $element: this.$element}; const locals = {$scope: this.componentScope, $element: this.$element};
const controller: any = const controller: any =
this.$controller(controllerType, locals, null, this.directive.controllerAs); this.$controller(controllerType, locals, null, this.directive.controllerAs);
this.$element.data(controllerKey(this.directive.name), controller); this.$element.data(controllerKey(this.directive.name !), controller);
return controller; return controller;
} }
@ -362,8 +365,8 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
} }
const key = controllerKey(name); const key = controllerKey(name);
if (startParent) $element = $element.parent(); if (startParent) $element = $element.parent !();
const dep = searchParents ? $element.inheritedData(key) : $element.data(key); const dep = searchParents ? $element.inheritedData !(key) : $element.data !(key);
if (!dep && !isOptional) { if (!dep && !isOptional) {
throw new Error(`Can not locate '${require}' in '${this.directive.name}'.`); throw new Error(`Can not locate '${require}' in '${this.directive.name}'.`);
} }

View File

@ -12,12 +12,12 @@ import * as angular from '../common/angular1';
// We store the ng1 injector so that the provider in the module injector can access it // We store the ng1 injector so that the provider in the module injector can access it
// Then we "get" the ng1 injector from the module injector, which triggers the provider to read // Then we "get" the ng1 injector from the module injector, which triggers the provider to read
// the stored injector and release the reference to it. // the stored injector and release the reference to it.
let tempInjectorRef: angular.IInjectorService; let tempInjectorRef: angular.IInjectorService|null;
export function setTempInjectorRef(injector: angular.IInjectorService) { export function setTempInjectorRef(injector: angular.IInjectorService) {
tempInjectorRef = injector; tempInjectorRef = injector;
} }
export function injectorFactory() { export function injectorFactory() {
const injector: angular.IInjectorService = tempInjectorRef; const injector: angular.IInjectorService|null = tempInjectorRef;
tempInjectorRef = null; // clear the value to prevent memory leaks tempInjectorRef = null; // clear the value to prevent memory leaks
return injector; return injector;
} }

View File

@ -99,7 +99,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
// We will be instantiating the controller in the `ngOnInit` hook, when the first `ngOnChanges` // We will be instantiating the controller in the `ngOnInit` hook, when the first `ngOnChanges`
// will have been already triggered. We store the `SimpleChanges` and "play them back" later. // will have been already triggered. We store the `SimpleChanges` and "play them back" later.
private pendingChanges: SimpleChanges; private pendingChanges: SimpleChanges|null;
private unregisterDoCheckWatcher: Function; private unregisterDoCheckWatcher: Function;
@ -152,7 +152,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
const bindToController = this.directive.bindToController; const bindToController = this.directive.bindToController;
if (controllerType) { if (controllerType) {
this.controllerInstance = this.buildController( this.controllerInstance = this.buildController(
controllerType, this.$componentScope, this.$element, this.directive.controllerAs); controllerType, this.$componentScope, this.$element, this.directive.controllerAs !);
} else if (bindToController) { } else if (bindToController) {
throw new Error( throw new Error(
`Upgraded directive '${this.directive.name}' specifies 'bindToController' but no controller.`); `Upgraded directive '${this.directive.name}' specifies 'bindToController' but no controller.`);
@ -165,7 +165,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
// Require other controllers // Require other controllers
const directiveRequire = this.getDirectiveRequire(this.directive); const directiveRequire = this.getDirectiveRequire(this.directive);
const requiredControllers = const requiredControllers =
this.resolveRequire(this.directive.name, this.$element, directiveRequire); this.resolveRequire(this.directive.name !, this.$element, directiveRequire);
if (this.directive.bindToController && isMap(directiveRequire)) { if (this.directive.bindToController && isMap(directiveRequire)) {
const requiredControllersMap = requiredControllers as{[key: string]: IControllerInstance}; const requiredControllersMap = requiredControllers as{[key: string]: IControllerInstance};
@ -187,7 +187,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
// Hook: $doCheck // Hook: $doCheck
if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) { if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
const callDoCheck = () => this.controllerInstance.$doCheck(); const callDoCheck = () => this.controllerInstance.$doCheck !();
this.unregisterDoCheckWatcher = this.$componentScope.$parent.$watch(callDoCheck); this.unregisterDoCheckWatcher = this.$componentScope.$parent.$watch(callDoCheck);
callDoCheck(); callDoCheck();
@ -204,8 +204,8 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
} }
const attachChildNodes: angular.ILinkFn = (scope, cloneAttach) => const attachChildNodes: angular.ILinkFn = (scope, cloneAttach) =>
cloneAttach(contentChildNodes); cloneAttach !(contentChildNodes);
linkFn(this.$componentScope, null, {parentBoundTranscludeFn: attachChildNodes}); linkFn(this.$componentScope, null !, {parentBoundTranscludeFn: attachChildNodes});
if (postLink) { if (postLink) {
postLink(this.$componentScope, this.$element, attrs, requiredControllers, transcludeFn); postLink(this.$componentScope, this.$element, attrs, requiredControllers, transcludeFn);
@ -272,12 +272,12 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
} }
private getDirectiveRequire(directive: angular.IDirective): angular.DirectiveRequireProperty { private getDirectiveRequire(directive: angular.IDirective): angular.DirectiveRequireProperty {
const require = directive.require || (directive.controller && directive.name); const require = directive.require || (directive.controller && directive.name) !;
if (isMap(require)) { if (isMap(require)) {
Object.keys(require).forEach(key => { Object.keys(require).forEach(key => {
const value = require[key]; const value = require[key];
const match = value.match(REQUIRE_PREFIX_RE); const match = value.match(REQUIRE_PREFIX_RE) !;
const name = value.substring(match[0].length); const name = value.substring(match[0].length);
if (!name) { if (!name) {
@ -335,7 +335,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
private extractChildNodes(element: Element): Node[] { private extractChildNodes(element: Element): Node[] {
const childNodes: Node[] = []; const childNodes: Node[] = [];
let childNode: Node; let childNode: Node|null;
while (childNode = element.firstChild) { while (childNode = element.firstChild) {
element.removeChild(childNode); element.removeChild(childNode);
@ -377,13 +377,14 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
// Quoted properties below so that this code can be optimized with Closure Compiler. // Quoted properties below so that this code can be optimized with Closure Compiler.
const locals = {'$scope': $scope, '$element': $element}; const locals = {'$scope': $scope, '$element': $element};
const controller = this.$controller(controllerType, locals, null, controllerAs); const controller = this.$controller(controllerType, locals, null, controllerAs);
$element.data(controllerKey(this.directive.name), controller); $element.data !(controllerKey(this.directive.name !), controller);
return controller; return controller;
} }
private resolveRequire( private resolveRequire(
directiveName: string, $element: angular.IAugmentedJQuery, directiveName: string, $element: angular.IAugmentedJQuery,
require: angular.DirectiveRequireProperty): angular.SingleOrListOrMap<IControllerInstance> { require: angular.DirectiveRequireProperty):
angular.SingleOrListOrMap<IControllerInstance>|null {
if (!require) { if (!require) {
return null; return null;
} else if (Array.isArray(require)) { } else if (Array.isArray(require)) {
@ -392,11 +393,11 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
const value: {[key: string]: IControllerInstance} = {}; const value: {[key: string]: IControllerInstance} = {};
Object.keys(require).forEach( Object.keys(require).forEach(
key => value[key] = this.resolveRequire(directiveName, $element, require[key])); key => value[key] = this.resolveRequire(directiveName, $element, require[key]) !);
return value; return value;
} else if (typeof require === 'string') { } else if (typeof require === 'string') {
const match = require.match(REQUIRE_PREFIX_RE); const match = require.match(REQUIRE_PREFIX_RE) !;
const inheritType = match[1] || match[3]; const inheritType = match[1] || match[3];
const name = require.substring(match[0].length); const name = require.substring(match[0].length);
@ -407,10 +408,10 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
const ctrlKey = controllerKey(name); const ctrlKey = controllerKey(name);
if (startOnParent) { if (startOnParent) {
$element = $element.parent(); $element = $element.parent !();
} }
const value = searchParents ? $element.inheritedData(ctrlKey) : $element.data(ctrlKey); const value = searchParents ? $element.inheritedData !(ctrlKey) : $element.data !(ctrlKey);
if (!value && !isOptional) { if (!value && !isOptional) {
throw new Error( throw new Error(

View File

@ -202,7 +202,7 @@ export class UpgradeModule {
this.injector.get($INJECTOR); this.injector.get($INJECTOR);
// Put the injector on the DOM, so that it can be "required" // Put the injector on the DOM, so that it can be "required"
angular.element(element).data(controllerKey(INJECTOR_KEY), this.injector); angular.element(element).data !(controllerKey(INJECTOR_KEY), this.injector);
// Wire up the ng1 rootScope to run a digest cycle whenever the zone settles // Wire up the ng1 rootScope to run a digest cycle whenever the zone settles
// We need to do this in the next tick so that we don't prevent the bootup // We need to do this in the next tick so that we don't prevent the bootup

View File

@ -284,7 +284,7 @@ export function main() {
const element = html('<ng2></ng2>'); const element = html('<ng2></ng2>');
adapter.bootstrap(element, ['ng1']).ready((ref) => { adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toBe('It works'); expect(multiTrim(document.body.textContent !)).toBe('It works');
}); });
})); }));
@ -390,7 +390,7 @@ export function main() {
| modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}}; | modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}};
</div>`); </div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => { adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)) expect(multiTrim(document.body.textContent !))
.toEqual( .toEqual(
'ignore: -; ' + 'ignore: -; ' +
'literal: Text; interpolate: Hello world; ' + 'literal: Text; interpolate: Hello world; ' +
@ -398,7 +398,7 @@ export function main() {
'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;');
ref.ng1RootScope.$apply('name = "everyone"'); ref.ng1RootScope.$apply('name = "everyone"');
expect(multiTrim(document.body.textContent)) expect(multiTrim(document.body.textContent !))
.toEqual( .toEqual(
'ignore: -; ' + 'ignore: -; ' +
'literal: Text; interpolate: Hello everyone; ' + 'literal: Text; interpolate: Hello everyone; ' +
@ -599,7 +599,7 @@ export function main() {
ng1Module.directive('rootComponent', adapter.downgradeNg2Component(RootComponent)); ng1Module.directive('rootComponent', adapter.downgradeNg2Component(RootComponent));
document.body.innerHTML = '<root-component></root-component>'; document.body.innerHTML = '<root-component></root-component>';
adapter.bootstrap(document.body.firstElementChild, ['myExample']).ready((ref) => { adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('It works!'); expect(multiTrim(document.body.textContent)).toEqual('It works!');
ref.dispose(); ref.dispose();
}); });
@ -1873,7 +1873,7 @@ export function main() {
document.body.innerHTML = '<ng2 name="World">project</ng2>'; document.body.innerHTML = '<ng2 name="World">project</ng2>';
adapter.bootstrap(document.body.firstElementChild, ['myExample']).ready((ref) => { adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => {
expect(multiTrim(document.body.textContent)) expect(multiTrim(document.body.textContent))
.toEqual('ng2[ng1[Hello World!](transclude)](project)'); .toEqual('ng2[ng1[Hello World!](transclude)](project)');
ref.dispose(); ref.dispose();

View File

@ -263,7 +263,7 @@ export function main() {
// an ng2 injector so it should use the `moduleInjector` instead. // an ng2 injector so it should use the `moduleInjector` instead.
const compiled = $compile('<ng2></ng2>'); const compiled = $compile('<ng2></ng2>');
const template = compiled($scope); const template = compiled($scope);
$element.append(template); $element.append !(template);
} }
}; };
} }
@ -404,7 +404,7 @@ export function main() {
const modFactory = compiler.compileModuleSync(LazyLoadedModule); const modFactory = compiler.compileModuleSync(LazyLoadedModule);
const childMod = modFactory.create(modInjector); const childMod = modFactory.create(modInjector);
const cmpFactory = const cmpFactory =
childMod.componentFactoryResolver.resolveComponentFactory(LazyLoadedComponent); childMod.componentFactoryResolver.resolveComponentFactory(LazyLoadedComponent) !;
const lazyCmp = cmpFactory.create(componentInjector); const lazyCmp = cmpFactory.create(componentInjector);
expect(lazyCmp.instance.module).toBe(childMod.injector); expect(lazyCmp.instance.module).toBe(childMod.injector);

View File

@ -29,7 +29,7 @@ export function main() {
it('should handle deferred bootstrap', fakeAsync(() => { it('should handle deferred bootstrap', fakeAsync(() => {
let applicationRunning = false; let applicationRunning = false;
let stayedInTheZone: boolean; let stayedInTheZone: boolean = undefined !;
const ng1Module = angular.module('ng1', []).run(() => { const ng1Module = angular.module('ng1', []).run(() => {
applicationRunning = true; applicationRunning = true;
stayedInTheZone = NgZone.isInAngularZone(); stayedInTheZone = NgZone.isInAngularZone();

View File

@ -316,7 +316,7 @@ export function main() {
'$httpBackend', '$httpBackend',
(method: string, url: string, post?: any, callback?: Function) => (method: string, url: string, post?: any, callback?: Function) =>
setTimeout( setTimeout(
() => callback(200, `${method}:${url}`.toLowerCase()), 1000)); () => callback !(200, `${method}:${url}`.toLowerCase()), 1000));
// Define `Ng2Module` // Define `Ng2Module`
@NgModule({ @NgModule({
@ -367,7 +367,7 @@ export function main() {
'$httpBackend', '$httpBackend',
(method: string, url: string, post?: any, callback?: Function) => (method: string, url: string, post?: any, callback?: Function) =>
setTimeout( setTimeout(
() => callback(200, `${method}:${url}`.toLowerCase()), 1000)); () => callback !(200, `${method}:${url}`.toLowerCase()), 1000));
// Define `Ng2Module` // Define `Ng2Module`
@NgModule({ @NgModule({
@ -518,8 +518,8 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
const ng1 = element.querySelector('ng1'); const ng1 = element.querySelector('ng1') !;
const ng1Controller = angular.element(ng1).controller('ng1'); const ng1Controller = angular.element(ng1).controller !('ng1');
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
@ -593,8 +593,8 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
const ng1 = element.querySelector('ng1'); const ng1 = element.querySelector('ng1') !;
const ng1Controller = angular.element(ng1).controller('ng1'); const ng1Controller = angular.element(ng1).controller !('ng1');
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
@ -670,8 +670,8 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
const ng1 = element.querySelector('ng1'); const ng1 = element.querySelector('ng1') !;
const ng1Controller = angular.element(ng1).controller('ng1'); const ng1Controller = angular.element(ng1).controller !('ng1');
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
@ -741,8 +741,8 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
const ng1 = element.querySelector('ng1'); const ng1 = element.querySelector('ng1') !;
const ng1Controller = angular.element(ng1).controller('ng1'); const ng1Controller = angular.element(ng1).controller !('ng1');
expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar'); expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar');
@ -911,10 +911,10 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
const ng1s = element.querySelectorAll('ng1'); const ng1s = element.querySelectorAll('ng1') !;
const ng1Controller0 = angular.element(ng1s[0]).controller('ng1'); const ng1Controller0 = angular.element(ng1s[0]).controller !('ng1');
const ng1Controller1 = angular.element(ng1s[1]).controller('ng1'); const ng1Controller1 = angular.element(ng1s[1]).controller !('ng1');
const ng1Controller2 = angular.element(ng1s[2]).controller('ng1'); const ng1Controller2 = angular.element(ng1s[2]).controller !('ng1');
expect(multiTrim(element.textContent)) expect(multiTrim(element.textContent))
.toBe( .toBe(
@ -998,8 +998,8 @@ export function main() {
const element = html(`<ng2></ng2>`); const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
const ng1 = element.querySelector('[ng1]'); const ng1 = element.querySelector('[ng1]') !;
const ng1Controller = angular.element(ng1).controller('ng1'); const ng1Controller = angular.element(ng1).controller !('ng1');
expect(multiTrim(element.textContent)) expect(multiTrim(element.textContent))
.toBe('ng1 - Data: [1,2,3] - Length: 3 | ng2 - Data: 1,2,3 - Length: 3'); .toBe('ng1 - Data: [1,2,3] - Length: 3 | ng2 - Data: 1,2,3 - Length: 3');
@ -1028,7 +1028,7 @@ export function main() {
// Define `ng1Component` // Define `ng1Component`
const ng1ComponentA: angular.IComponent = {template: 'ng1A(<ng1-b></ng1-b>)'}; const ng1ComponentA: angular.IComponent = {template: 'ng1A(<ng1-b></ng1-b>)'};
const ng1DirectiveB: angular.IDirective = { const ng1DirectiveB: angular.IDirective = {
compile: tElem => grandParentNodeName = tElem.parent().parent()[0].nodeName compile: tElem => grandParentNodeName = tElem.parent !().parent !()[0].nodeName
}; };
// Define `Ng1ComponentAFacade` // Define `Ng1ComponentAFacade`
@ -1088,7 +1088,7 @@ export function main() {
} }
isPublished() { isPublished() {
return this.$element.controller('ng1') === this ? 'published' : 'not-published'; return this.$element.controller !('ng1') === this ? 'published' : 'not-published';
} }
verifyIAmAClass() { this.isClass = 'isClass'; } verifyIAmAClass() { this.isClass = 'isClass'; }
@ -1314,7 +1314,7 @@ export function main() {
name = 'world'; name = 'world';
constructor($element: angular.IAugmentedJQuery) { constructor($element: angular.IAugmentedJQuery) {
getCurrentContent = () => $element.text(); getCurrentContent = () => $element.text !();
compiledContent = getCurrentContent(); compiledContent = getCurrentContent();
} }
} }

View File

@ -4,6 +4,7 @@
"declaration": true, "declaration": true,
"stripInternal": true, "stripInternal": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"strictNullChecks": true,
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "../../dist/packages/upgrade", "outDir": "../../dist/packages/upgrade",

View File

@ -18,7 +18,7 @@ export declare class UpgradeAdapterRef {
ng2Injector: Injector; ng2Injector: Injector;
ng2ModuleRef: NgModuleRef<any>; ng2ModuleRef: NgModuleRef<any>;
dispose(): void; dispose(): void;
ready(fn: (upgradeAdapterRef?: UpgradeAdapterRef) => void): void; ready(fn: (upgradeAdapterRef: UpgradeAdapterRef) => void): void;
} }
/** @stable */ /** @stable */