Check out our Angular Book Series.

Using `as type` - Type Assertions in TypeScript - Part 1

In an earlier article I wrote a bit about creating get/set properties in TypeScript. I am working on a project that uses a bunch of these, and sometimes they don't work.

Why do my get/set properties returned undefined? The method never executes, how can I fix it?

I'm going to show you why you're having problems and along the way talk about different forms of type conversions in TypeScript (and JavaScript).

The Setup

Let's start by creating a TypeScript class:


export class TestClass {
numbers: number[];
counter = 0;

get sum() {
this.counter++;
return this.numbers.reduce((accumulator, currentValue) =>
{
return accumulator + currentValue;
});
}
}

This class is named TestClass. It has three properties:

  • numbers: A regular property that contains an array of numbers
  • counter: A regular property that contains the number of the times that the sum was processed, perhaps a value you want to store for internal auditing purposes.
  • sum: A get property that returns the sum of all the values in the numbers array. Since this is a get property with no set, it is essentially read only and cannot set the value through traditional assignment.

Accessing a Get method with Simple JSON

When returning data from a server, I often get JSON, which is viewed as a generic object not tied to any specific TypeScript class. Look at code like this:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON.sum); // compile error

The first line hard codes a generic object, just like JSON that would be returned from the server to the application. this JSON matches the TestClass. But, the second line will give a compile error:

I can get this to compile if I tweak the code a bit differently:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON['sum']); // returns undefined

But, alas, that does not work, either:

The value is returned as undefined. The browser things this JSON value is a simple object:

There is no property named sum on a generic JavaScript object, and therefore cannot introspect special properties on the TestClass object.

For our get/set properties to work we need to perform some type of conversion from our generic JSON object to our formal type.

as TestClass

One version of Type assertion in TypeScript is similar to a cast that I've used in other languages.


const testClassAs = {numbers : [1, 2, 3, 4]} as TestClass;
console.log(testClassAs.sum); // returns undefined

Put this in your app and it should compile fine without any errors about the sum property not existing. That is progress. But, run the code and you see similar errors. The output to the console is undefined:

And the object in the debug tools is still seen as a generic object:

What gives? The `as type` is a TypeScript compile time assertion and has no affect at runtime. No conversion is made between your generic JSON class and your better typed TypeScript class. TypeScript does not even call this casting, because of the loosely typed nature of JavaScript. It calls it type assertion.

The angle bracket syntax of type assertion has the same problems.

For get/set properties to work, you must create an instance of that class somehow. I'm going to delve into that next week.

How do I run extra code when I set a value in TypeScript?

Every once in a while something I'll want to run code when a value is set on a class. Maybe I'll want to validate the input, or maybe I'll want to add additional processing. This code should be built into the class instead of the consumer. TypeScript allows us to do this by creating get and set methods.

Simple Property

A simple class will be something like this:


export class TestClass {
numbers: number[];
counter: number;
}

I just borrowed this from another example I'm working on. It includes a numbers property, which is an array of number values, and a counter value, which is a single number.

To use this class, we create an instance of it:


const testClass = new TestClass();

Then we can access the values:


testClass.numbers = [1, 2, 3, 4];
console.log(testClass.counter);

This is standard and simple.

The Problem

Now let's assume that every time the numbers array is accessed we want to increment the counter. How can we do that? Well, we could do it in the consuming code:


testClass.numbers = [1, 2, 3, 4];
testClass.counter += 1;

But, then the class is less self countained, and we have to remember to update the counter every single time that the numbers is accessed. There must be a better solution.

Solution 1

We could add a method to the class:


setNumber(value) : {
this.numbers = value;
testClass.counter ++;
}

Then our calling code would be like this:


testClass.setNumber([1, 2, 3, 4]);

This is nice because it hides our internal implementation a bit, and would work, but from my consumer I don't want them to have to call a method.

Get/Set properties

Let's change the property into a get/set property. First, make numbers a private variable:


private _numbers: number[]

An underscore was added before the numbers to distinguish it from the public property.

Now, create a get method:


get numbers():number[] {
return this._numbers;
}

This is special syntax. Instead of a normal method, the keyword get is before it. All this does is return the value that represents our numbers property.

We'll also need a setter:


set numbers(value:numbers[]):void {
this._numbers - value;
}

That is great, now from within the consuming code, we treat the get / set methods just like we would a regular property and can access them using the object property notation:


testClass.numbers = [1, 2, 3, 4];
console.log(testClass.counter);

The first line sets the value, and calls the setter. The second line retrieves the value and calls the getter. The internal implementation of the class is unknown to the consumer.

Do more in the set

Inside our class there are get set methods. We can treat them just like any other method and put any code we want in there. For the purposes of this sample I'm going to increment the counter:


set numbers(value:numbers[]):void {
this._numbers - value;
this.counter++;
}

Now, we have side affects when we set the numbers value.

Final Thoughts

There is a lot of flexibility that can be had with getters and setters. For example, in one situation, I had to loop over an array returned rom a remote datasource and pick out one specific item. A get method did it for me, without cluttering up my main Angular component with extraneous data processing code.

Understanding The JavaScript Reducer Function

Despite how long I've been creating JavaScript applications, I keep learning new things and discovering new little pieces of the language that I didn't know existed. Today I found the reducer function.

The reducer will loop over an array, with the intent of reducing the full array into a single value. The most common use case of this is to add up all the numbers in an array, like this:


console.log([1, 2, 3, 4].reduce((accumulator, currentValue) =>
accumulator + currentValue));

The reducer function accepts two arguments, the first is the accumulator and the second is the currentValue.

The first time the reduce function runs, it passes in the first two values from the array. The accumulator is the first value, 1 in this case. The currentValue is the second value,. the 2.

The second time the function is executed it returns the results of the first function run into the accumulator, and the third function. In this case, 3 is the results of the first run, and 3 is the third element in the array.

The third time the reducer is called it gets 6--the results of the third run of the function--and 4--the fourth item in the array. Then it has no more items to execute and returns the results.

Adding numbers in an array is a simple use case for this, but this could be used in much more advanced situations too, such as looping over an array of objects. Imagine you are creating a log display and want to show all the users who have edited something. Just use reducer to get the users list on each log item. Or maybe you're dealing with rights limited content and want to figure out what country the content is in; this could help if you loop over an array of 'rights metadata' objects.

Play with the code here.

My Unit Tests are Running out of Order with Angular 8!

This is a weird one. I'm updating Unit Test from my LearnWith series for Angular 8. And I ran into a few tests that would inconsistently pass.

The app behind the LearnWith series is a task manager, and one of the tests that was failing was to mark a task completed.

Let's look at the test:


describe('completeTask() ', function () {
let task : TaskVO = {taskCategoryID:1,taskID:10,completed:true} as TaskVO;
};

This is a describe() block, for the completeTask() method and it also creates a default task.

I had two tests in this block. The first makes sure the task was completed:


it('Make task Completed', () =>
{
taskService.completeTask(task).subscribe(
value => {
expect(value.resultObject[0].completed).toBeTruthy();
});
const req = httpMock.expectOne(url) ;
req.flush({"resultObject":[task],"error":0});
}

I truncted it for simplicity. But, it takes the full task--defined as a constant in the describe block--passes that task into a service, creates a request, resolves it, and checks the value returned.

The same test suite had a test to mark a task not completE:


it('Make task Not Completed', () =>
{
task.completed = false;
taskService.completeTask(task).subscribe(
value => {
expect(value.resultObject[0].completed).toBeFalsy();
});
const req = httpMock.expectOne(url) ;
req.flush({"resultObject":[task],"error":0});
}

The second test sets the completed value on the task object to false; then runs very much the same code, and after the service is resolved; makes sure that the completed value is false.

The second test always ran without problems, but the first test would sporadically fail. My only explanation for this is that the tests must not be run in the same order on every execution of the test suite.

The task object is not reinitialized after every it() test, therefore the values can stay constant across multiple tests.

There are two solutions to this. The first is to make sure the first test sets the default value:


it('Make task Completed', () =>
{
task.completed = true;
// rest of test

That magically worked it.

The second solution is to move the task initialization into a beforeEach() block so it would be re-initialized before each test. That would look like this:


let task : TaskVO;

beforeEach(() =>
{
task = {taskCategoryID:1,taskID:10,completed:true} as TaskVO;
});

Either solution would solve the problem; and throughout my various tests I used one or the others depending upon what was failing.

Honestly, I'm surprised that this was not happening in versions of Angular prior to 8, so it took me a bit off guard.

Why can't Angular find the path() method on a Location object?

I'm writing some unit tests to test an Angular Router. In the test, I have code like this:


expect(location.path()).toBe('/something');

IntelliJ is giving me errors, saying it can't find the path value:

Clearly the path() method exists on the Angular Location object, so what was the cause of the error?

Apparently there is a JavaScript Location object.

The browser Location object does not contain a path() function even though the Angular one does.

Since Location exists natively, IntelliJ did not import the Angular library, and I didn't notice until I tried to run the code.

The fix is pretty simple. Just import the Angular Location library manually:


import {Location} from "@angular/common";

And you should be good to run your code and unit tests without any errors.

Angular 8 is Out

Angular 8 came out, and with it a new version of the Learn With Books.

I've gone through and updated everything. I've also added a brand new chapter to the Bonus book all about Angular Directives--that will be coming out soon.

Creating Angular Directives Part 5 - Applying One Directive to Different Elements

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties, and Part 4 which covers event dispatching.

We have created a directive named reverse which will toggle CSS Between two separate states.

Using the Directive Multiple Times

All our samples so far have been applying the styles to the button, but we can easily use this same directive on other elements; here it is in a p tag and a div:


<p [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a p!
</p>
<div [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a div!
</div>

The button is still in the view, and can be used to toggle:

Click the button and everything is reversed:

This is where we start to see the real power of encapsulating this in a directive. We are now writing simpler code than we would have if we were trying to do this using ngClass. Let's add four new styles into the create-attribute-directive.component.css:


.regular-red {
background: #ffffff;
color: #ff0000;
}

.reversed-red {
background: #ff0000;
color: #ffffff;
}

.regular-blue {
background: #ffffff;
color: #0000ff;
}

.reversed-blue {
background: #0000ff;
color: #ffffff;
}

The styles use red and white, or blue and white instead of our usual black and white. Apply them to HTML elements in create-attribute-directive-component.html:


<p [appReverse]="reversedState" regularCSSClass="regular-red" reversedCSSClass="reversed-red">
The directive in a p!
</p>

<div [appReverse]="reversedState" regularCSSClass="regular-blue" reversedCSSClass="reversed-blue">
The directive in a div!
</div>

The red style is applied to the p tag and the blue styles are applied to the div. Rerun the code:

And click to switch:

Final Thoughts

The bulk of Angular development I do is focused on creating custom components, not custom directives. But, understanding directives is important to being a good Angular developer because they give a different sort of flexibility that can be a benefit.

Be sure to check out my Learn With Series on Angular 8, which will cover this example in more detail, and even teach you all about Structural directives.

Creating Angular Directives Part 4 - Dispatching Events

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties.

We have created a directive named reverse which will toggle CSS Between two separate states.

Dispatching Events

A directive can dispatch its own events, just like a component can. Let's add an event to the directive that will dispatch whenever the state changes. First, I'll add a new class:


export class CSSReversedEvent {
addedCSSClass: string;
removedCSSClass: string;
}

I put this class in the reverse.directive.ts file, instead of creating its own class file. It includes one value for the CSS Class that was removed, and one for the CSS Class that was added.

Now inside the ReverseDirective class, add the output event:


@Output() stateChange: EventEmitter<CSSReversedEvent> = new EventEmitter();

This uses the @Output() metadata to create the EventEmitter named stateChange. How look at the changeState() method:


changeState() {
const newState: CSSReversedEvent = new CSSReversedEvent();
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
newState.addedCSSClass = this.reversedCSSClass;
newState.removedCSSClass = this.regularCSSClass;
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
newState.addedCSSClass = this.regularCSSClass;
newState.removedCSSClass = this.reversedCSSClass;
}
this.stateChange.emit(newState);

The first line in the method creates a new instance of the CSSReversedEvent class. The middle of the method will add the CSS Values onto this new object, depending on which state we are entering. The final name of the method will dispatch the event.

Open up the create-attribute-directive.html file and add in the stateChange event listener:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed"
(stateChange)="onStateChange($event)">

Reverse State
</button>
The event listener will call the onStateChange() event inside the create-attribute-directive.component.ts file:


onStateChange(event) {
console.log(event);
}

For simplicity I just outputted the event to the console.

Rerun the code and start clicking buttons:

During component initialization this event is dispatched twice. Once after the reversedState value is set, but before the regularCSSClass and reversedCSSClass are set. We see the event dispatching undefined for each class in this case. Then it is dispatched a second time after the initialization is complete. This is when the initial styles are applied to the button.

Click the button a few times to see the events continue to dispatch:

At this point in the series, you should realize that there is a lot you can do with directives.

What's Next?

For the last article in this series, I'm going to give a sample of applying the same directive to different elements.

Creating Angular Directives Part 3 - Exposing Properties

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2.

We created a directive named reverse which will toggle CSS Between two separate states.

Expose New Properties

The directive as is is hard coding the style values inside the directive. That is horrible use of encapsulation, and limits reuse. Let's open those up. Open up reverse.directive.ts:


@Input() regularCSSClass: string;
@Input() reversedCSSClass: string;

I added one input for the regularCSSClass and one for the reversedCSSClass. Now move to the changeState() function:


changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
}
}

Instead of accessing hard coded values as the CSS Class is added, or removed, from the native element the variables are added.

Notice how the values have no default styles. To solve that we'll make sure to call the changeState() method when ngOnInit() runs, which will be after the property values are set. First implement the OnInit interface as part of the class definition:


export class ReverseDirective implements OnInit {

Then add the ngOnInit() method:


ngOnInit() {
this.changeState();
}

This will make sure that the default states are set after the component is initialized. Open up create-attribute-directive.component.html and add in our two new properties:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

Reverse State
</button>

Angular's magic under the hood will know the new attributes belong to the directive and will pass in those values.

Rerun the app:

Then click the button:

The new Angular directive inputs were set up as regular HTML attributes with string values, but we could set them up as Angular attributes with an Angular expression as the value. In the simplest form, like this:


<button (click)="reverseState()"
[appReverse]="reversedState"
[regularCSSClass]="'regular'"
[reversedCSSClass]="'reversed'">

Reverse State
</button>

The Angular expression is a literal string, and the regularCSSClass and reversedCSSClass are enclosed in brackets, signifying they are properties.

What's Next?

The next part of this series will show you how to use events as part of a directive.

Creating Angular Directives Part 2 - Using Renderer2

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to do a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive. We created a directive named reverse which will toggle CSS Between two separate states.

Using Renderer

If you read the docs on the ElementRef's nativeElement property, there is a big warning to avoid using it. It breaks encapsulation by accessing the DOM directly, and can lead to unexpected results in the application.

We're going to use the Renderer2 component instead. It is designed to give a layer of abstraction between Angular and the DOM within directives like this. While we're at it, I'm also going to switch to using a CSS Class instead of accessing styles directly.

The first step is to inject the Renderer2 into the directive's reverse.directive.ts file:


constructor(private renderer: Renderer2, private el: ElementRef) { }

The reversedState property remains unchanged, but we will want to modify the changeState() method. This is the current method:


changeState() {
if (this.reversedState) {
this.el.nativeElement.style.backgroundColor = '#000000';
this.el.nativeElement.style.color = '#ffffff';
} else {
this.el.nativeElement.style.backgroundColor = '#ffffff';
this.el.nativeElement.style.color = '#000000';
}
}

This uses the nativeElement to change the DOM directly. Widely considered a bad a practice.

Change it to use the renderer2 to add and remove classes:


changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, 'regular');
this.renderer.addClass(this.el.nativeElement, 'reversed');
} else {
this.renderer.removeClass(this.el.nativeElement, 'reversed');
this.renderer.addClass(this.el.nativeElement, 'regular');
}
}

Instead of drilling down into the nativeElement directly, we're calling the addClass() and removeClass() methods on the renderer, and passing in the nativeElement along with the new style. We could have done the same thing with the previous sample, using addStyle() and removeStyle() methods on the renderer.

Let's be sure to add our regular and reversed styles to create-attribute-directive.css:


.regular {
background: #ffffff;
color: #000000;
}

.reversed {
background: #000000;
color: #ffffff;
}

Rerun the code:

Then click the button:

There are no change from the previous implementation, we just have a different, better, implementation under the hood.

What's Next?

Part 3 of this series will show you how to use properties in your component so that you do not have to hard code styles inside it.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.