Check out our Angular Book Series.

How do I import something in Vanilla JavaScript

I've been doing so much with Angular and TypeScript that jumping back to regular JavaScript is a bit of a sticker shock. I've become very comfortable with a lot of the benefits of using TypeScript, specially how it magically handles importing other libraries.

I've been working on a book about RxJS, and using vanilla JavaScript instead of an advanced framework. This is part of my goal, when writing, to avoid as many dependencies as possible. And you shouldn't need to know about TypeScript in order to use a JavaScript library.

In TypeScript I might import things like this:


import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

And that works great. I stumbled a bit translating that into JavaScript, though. This is how it is done:


const { Observable } = rxjs;
const { tap } = rxjs.operators;

Instead of using the import tag, I create constants that point to the library. Instead of using the `from` we are assigning the constant at the relevant library. the Observable points to the full rxjs library--which I'm loading from a CDN using a script tag. The pipeable tap() function points to rxjs.operators.

Took me some trial and error to figure this out, so I hope this helps you.

How do I give an Enum an object for a value?

The short answer is that you can't. Enums must be simple values. However, I found a creative work around that I quite like and I'm going to explain it here. If you haven't dealt with Enums a lot, check out my introductory post from last week.

The Problem

I recently wanted to use an object as the value for an enum. Let's pretend I am creating a hide and seek game. I have a bunch of characters that can be hidden:


export enum Character {
JEFFRY = 'Jeffry',
JOHNNY = 'Johnny',
JIMBO = 'Jimbo'
}

and a bunch of locations that a character can hide:


export enum Location {
LIBRARY = 'library',
SWAMP = 'swamp',
CASTLE = 'castle',
STUDY = 'study'
}

I wanted to create an enum for all possible places a character would hide. The object would look something like this:


export class HidingSpotVo {
character: Character;
location: Location;
}

And if I try to store a bunch of these object instances in an enum, it might be like this:


export enum HidingSpot {
JEFFRY_IN_LIBRARY = Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.LIBRARY});
JEFFRY_IN_CASTLE = Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.CASTLE});
JIMBO_IN_STUDY = Object.assign(new HidingSpotVo(), {character: Character.JIMBO, location: Location.STUDY})
}

I could add a lot more combinations here. This will cause all sorts of errors, because the value of an enum cannot be an object:

That doesn't help us solve our goal.

Create an Enum Class

My solution was to create a class that could give us similar functionality of the enum. Start with the class definition:


export class HidingSpot {
}

You've probably seen this a million times before. Now add a constructor:


private constructor(private hidingSpot: HidingSpotVo) {}

The constructor is marked as private. This is odd, but it prevents the consumers of this class from creating new instances of this. It is a trick that allows us to create a singleton. A hidingSpot value is passed into the constructor; and make private across the instance.

But, if the constructor is private, how do we create instances of this class? We do it from the inside the class:


static readonly JEFFRY_IN_LIBRARY = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.LIBRARY})
);

This is a static property, so we access the value on the class; not on an instance of the class. I also made the property read only so that it cannot be changed. We pass in an instance of the HidingSpotVo with the two cross sectional values, representing JEFFRY_IN_LIBRARY. We can use the same approach for some of our other values:


static readonly JEFFRY_IN_CASTLE = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.CASTLE})
);
static readonly JIMBO_IN_STUDY = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JIMBO, location: Location.STUDY})
);

We can use this new class in the same way we can use an enum. First, an example of using it as the type of a variable:


private _hidingSpot: HidingSpot;

Then an example of using it as a return type for a function:


get hidingSpot(): HidingSpot {
return this._hidingSpot;
}

And finally, an example using it as an argument type for a method argument:


set hidingSpot(value: HidingSpot) {
this._hidingSpot = value;
}

We can set the value of this variable:


this.hidingSpot = HidingSpot.JEFFRY_IN_CASTLE;

And output it:


console.log(this.hidingSpot);

The output will give us an instance of the object.

Although, this isn't formally an enum, it is used in much the same manner and have a concrete list of non-editable values that can be referred used like a class and a constant at the same time.

What are Enums?

I've been working with Angular and Typescript for quite some time. They have a special data type called an Enum. This post will tell you all about them.

The Definition

An Enum is a data type where one value represents another valu. Enums are like a cross between a class and a constant. In TypeScript an enum looks like this:


export enum Character {
JEFFRY = 'Jeffry',
JOHNNY = 'Johnny',
JIMBO = 'Jimbo'
}

This character enum is a list of names. They have a controlled vocabulary of values under the same data type. This is how we might use an enum:

  • As the return type from a function
  • As an argument type into a function
  • As a variable type

We can demonstrate these pretty easily by creating a get / set property on a TypeScript class. First create a private variable:


private _character: Character;

This demonstrates using an enum as a variable type. Then create a get method:


get character(): Character {
return this._character;
}

This represents using an enum as the return type. The internal _character value is returned. Now, add a set method:


set character(value: Character) {
this._character = value;
}

This shows how you can use the enum as an argument into a function. You'll set the value something like this:


this.character = Character.JEFFRY;

which references one of the specific values in the Character enum. You can also output it:


console.log(this.character);

Which will give you the text value representing the enum. Enums can be powerful and I use them often when I need to represent a controlled vocabulary inside the angular apps I build.

Enum values must be primitive data types, such as strings, numbers, or boolean values. They cannot be objects. That is what I'm going to tackle next week.

Why is my Angular Linter throwing errors on private variables with underscores?

I was starting a new project on my local dev machine, and was creating a get set method inside an Angular class. It was something like this:


private _myFoo: string;
get myFoo(): string {
return this._myFoo;
}
set myFoo(value: string) {
this._myFoo = value;
}

This is a pretty standard implementation, however I noticed an error was showing on the first line:

The error was:

TSLint: variable name must be in lowerCamelCase, PascalCase or UPPER_CASE(variable-name)

I had never seen that before and the code still compiled, so what was going on here?

This was a linting error and to fix it I had to modify the linting settings for the project.

In the Angular project I opened up tslint.json file and added this rule to the end:


"variable-name": {
"options": [
"allow-leading-underscore"
]
}

Go here for more info on this variable-name linting rule.

Once I added this, linting started working as expected. I'm pretty surprised that the Angular linter was displaying this error by default.

Using `Object.assign()` - Type Assertions in TypeScript - Part 2

Last week I wrote about using `as type` in TypeScript to perform type assertions. The gist is that you convert a generic object, or JSON object into a custom object, like this:


myJSON as MyCustomClass

Once you do that, IDEs can introspect the object for code hinting purposes, and the TypeScript compiler will show errors if you access non-existent properties or methods. The problem is that this is just a compile time syntax and does not perform runtime type conversions. The use of get/set properties in the underlying object will not throw compiler errors, but will also fail in the UI code.

Thankfully there is another way.

Object.assign()

Built right into modern versions is Object.assign(). What this can be used for is move all the properties from one object into another. Any existing properties will be overwritten. Any new properties will be added to the object.

Here is a quick sample modeled after the link above:


const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
Object.assign(target, source);
console.log(target);
console.log(source);

The target object has two properties: a and b. The source object has two properties: b and c. After object.assign() is executed, the target object will have three properties: a, b, and c. The original value of b--2--will be replaced with the source's value for b--4.

Run this in a browser:

Simple enough.

Using Object.assign() as Type Conversion

How do we use an Object.assign() to convert regular JSON to an instance of our custom class? You can find our custom class sample in last week's article.


const testClassAssign = Object.assign(new TestClass(), {numbers : [1, 2, 3, 4]});
console.log(testClassAssign.sum); // returns 10

The first argument to the Object.assign() is a brand new instance of the TestClass. This instance gives us access to all the properties and methods in the class, including the get/set properties. The second argument is our custom JSON, or other generic object. All the properties from the generic object will be copied over to the new TestClass instance, essentially creating our full object:

You see in Chrome Dev tools that the new resulting class has the full type listed. Look at the console and you'll see the proper output for the second line:

This is what we wanted, and is important if you want to access any sort of custom method inside your class, while also touching on properties.

You can get all the samples from these two blog articles from my Github account.

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.

How do I get an Array of all the Keys in a JavaScript Map?

I'm working on an Angular application and want to loop over all the keys in a JavaScript map. A map is a key value pair data type, like an object, but geared for dynamic properties. In the ColdFusion world we called this a structure, and in ActionScript we called it a dictionary, but the concept is the same.

I can create a map and add items to it, like this:


let myMap = new Map();
myMap.set('foo', 'bar');
myMap.set('bar', 'Barbar');
myMap.set('foobar', 'BarbarFooFoo');

You can look at the map like this:

Once it has a set of keys, I can get the keys using this:


myMap.keys();

This is an object, or more specifically an iterator. But, I want the keys as an array.

One trick is to convert the iterator to an array using Array.from():


Array.from( hydratedImageMap.keys() );

A more 'ES6' technique would be to use the spread operator:


[ ...hydratedImageMap.keys() ]

You'll see similar output:

Not all that hard! Get the code here or play with it here.

How do I make a TypeScript property that could have multiple types?

I'm working on an app for a client and as with many apps was displaying a list of items. I needed to loop over this list and display items. Every UI framework has some way to do this.

This was an Angular app using TypeScript, so I making use of TypeScript's statically typed nature. My problem was that the objects in this list could be one of two types, let's call those Type1 or Type2. I was running into errors when transpiling the code. I had defined the type like this on the class:


myItems: Type1[];

This code created an array of Type1 arguments. IT wasn't until later that Type2 was added as a possible value in this list.

When updating the code to accommodate for Type2 I realized that sometimes I was receiving errors by accessing Type2 specific properties on a Type1 argument. What was the solution? I used something called Union types. I set up my value like this:


myItems: (Type1 | Type2)[];

This means that myItems can be a mixed array of Type1 and Type2 values.

That works great as long as all properties that you access in Type1 are also in Type2. If a property that you're accessing in one and not the other exists, then you'll get errors--these were the same errors I started with. I solved that issue by adding blank getters to the class definition:


get mySharedProperty(){ return null};

Far from perfect, but functional for my purposes.

Maybe I should have just created an interface and had both Type1 and Type2 extend it?

How to spy on a Property with Karma?

When writing unit tests, SpyOn, is used to watch and manipulate a method call, potentially returning your own data. This is used to easily mock external component calls so that your unit test can focus on the class in question without worrying about complications or side affects from external dependencies. I found myself in a situation where I had a class and that class had a read only get() property. I was creating my own Angular service wrapper for the Dragula drag and drop library. I was exposing some drop and remove listeners get methods.

I wanted to control the results returned from that get method. This was not a situation where I could set the underlying value because there was no set method. But, spyOn would not work because a get() method is viewed as a property, not a method. The class code was conceptually like this:


export class MyClass {

constructor(private dragula: DragulaService){
}

get dropListener(){
return this.dragula.drop('myDragulaGroup');
}
}

My code was using Angular, so the DragulaService was injected into this component, and the dropListener was exposed via a get.

For the purposes of unit testing, I want complete control over that drop listener Observable. Thankfully, spyOnProperties would give me that control.

The unit test would be a bit like this:


it("Should spy on Observable", () =>
{
const myClassInstance = new MyClass();

let dropObserver: Observable<any>;
const dropObservable: Observable<any> = Observable.create( ( ObserverArg: Observer<any>) => {
dropObserver= ObserverArg;
}

mySpy = spyOnProperty(myClassInstance, 'dropListener', 'get').and.returnValue(dropObservable);

I'm gonna take a quick break to explain spyOnProperty. It takes three parameters:

  • Class: The class instance that contains the property you want to watch.
  • Property: The name of the property being watched.
  • Accessor: The Access Type of the method being watched, in this case get.

Note that we are storing the results of the spyOnProperty in the mySpy variable. This is optional when using spyOn, but for spyOnProperty it is required. The unit test could would continue:


const val = myClassInstance.dropListener;

All that line does is access the dropListener property inside the class, which should trigger the spy. Now we can test against the access:


expect(mySpy ).toHaveBeenCalled();
});

In a more advanced unit test, we could subscribe to the dropListener inside the test, and use dropObserver.next() to trigger the result handler in an async block.

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.