Using NgOnChanges Collection With Dot-Notation And TypeScript In Angular 2.4.4
A couple of months ago, I looked at using dot-notation vs. array or bracket notation with TypeScript objects that have generic key-value interfaces. In that post, I demonstrated that you needed to use array-notation or the TypeScript transpiler will complain. One of the places in which this has continued to be a nuisance is the ngOnChanges() life-cycle method in Angular 2 components. Lately, however, I have started sub-classing the SimpleChanges interface in order to allow for the more natural dot-notation.
If you look at the SimpleChanges interface in the Angular 2 source code, you can see that it uses a generic key-value map:
export interface SimpleChanges { [propName: string]: SimpleChange; }
This generic interface forces us to use array-notation / bracket-notation in our ngOnChanges() life-cycle method. So, for example, if I had an Angular 2 component that accepted an Input binding, the use of dot-notation when inspecting the ngOnChanges() argument would throw an error:
// Import the core angular services.
import { Component } from "@angular/core";
import { OnChanges } from "@angular/core";
import { SimpleChanges } from "@angular/core";
@Component({
moduleId: module.id,
selector: "my-widget",
inputs: [ "value" ],
template:
`
<strong>Value</strong>: {{ value }}
`
})
export class MyWidgetComponent implements OnChanges {
public value: string;
// I initialize the emoticon button component.
constructor() {
this.value = "";
}
// I get called whenever the bound inputs change (including the first binding).
public ngOnChanges( changes: SimpleChanges ) : void {
if ( changes.value && ! changes.value.isFirstChange() ) {
console.log(
"Value change from",
changes.value.previousValue,
"to",
changes.value.currentValue
);
}
}
}
Here you can see that I am declaring the ngOnChanges() argument as type SimpleChanges. And, when I try to use dot-notation to inspect the "changes.value" property, TypeScript logs the following error:
Property 'value' does not exist on type 'SimpleChanges'. (TS2339)
To get around this problem, I've started to sub-class the SimpleChanges interface within the component, explicitly defining the input properties that I expect to consume:
interface InputChanges extends SimpleChanges {
value?: SimpleChange;
}
This creates a new interface that extends the generic key-value mapping of the SimpleChanges interface, but also provides for an optional and explicit ".value" property. Now, in my Angular 2 component, I can use this interace when defining my ngOnChanges() life-cycle method:
// Import the core angular services.
import { Component } from "@angular/core";
import { OnChanges } from "@angular/core";
import { SimpleChange } from "@angular/core";
import { SimpleChanges } from "@angular/core";
interface InputChanges extends SimpleChanges {
value?: SimpleChange;
}
@Component({
moduleId: module.id,
selector: "my-widget",
inputs: [ "value" ],
template:
`
<strong>Value</strong>: {{ value }}
`
})
export class MyWidgetComponent implements OnChanges {
public value: string;
// I initialize the emoticon button component.
constructor() {
this.value = "";
}
// I get called whenever the bound inputs change (including the first binding).
public ngOnChanges( changes: InputChanges ) : void {
if ( changes.value && ! changes.value.isFirstChange() ) {
console.log(
"Value change from",
changes.value.previousValue,
"to",
changes.value.currentValue
);
}
}
}
This time, when I run the Angular 2 application, everything works perfectly; TypeScript doesn't complain about my use of "changes.value" because the newly sub-classed interface defines an explicit ".value" property.
TypeScript definitely takes some getting used to. But, the more I use it, the more I like it. It really forces me to think about what data I can count on; and, what data may exist, but is unsafe to reference. Sub-classing the SimpleChanges interface adds explicitness to my Angular 2 components and allows me to use dot-notation without error.
Want to use code from this post? Check out the license.
Reader Comments
This might get better in the next release of typescript (2.2). See:
https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#dotted-property-for-types-with-string-index-signatures
Nice article,informative
The site contains a very great blog. the information present in this site will be very useful for us. thank you for sharing the blog with us.
A really good idea. Thanks for this post!
For my part, I love TypeScript even more than JavaScript. Quality and readability is so much higher with typings.
I'm excited to see this being "fixed" in TypeScript 2.2. Woot and double-woot!