Sep 30, 2020

Angular component field initialization

In my previous post, I talked about Class field initialization in typescript. How about field initialization of angular component, is it different? Angular component is defined an typescript class. It should follow same logics. However, Angular component has life cycle. The ngOnInit is special method that angular will run angular first displays the data-bound properties and sets the directive or component's input properties. So if your initialization code depends on these data-bound proprties and input properties, you can not run them in constructor. So the following code doesn't work

@Component({
  //..
})
class MyComponent {

  //angular specific
  @Input() firstName: string;
  @Input() lastName: string;

  fullName: string;

  constructor() {
    //this does not work
    this.fullName = this.firstName + ',' + this.lastName;
  }
}

You have to run this code in the ngOnInit method like below.

@Component({
  //..
})
class MyComponent {

  //angular specific
  @Input() firstName: string;
  @Input() lastName: string;

  fullName: string;

  ngOnInit() {
    this.fullName = this.firstName + ',' + this.lastName;
  }

}

But some people take it too far. Since it is safter to run in ngOnInit method, why not always put all initialize code in this method. And So the following initialization code become very popular, even the initialization code has no dependency of angular data-bound proprties and input properties.

@Component({
  //..
})
class ProductComponent {

  displayCode$: Observable<boolean>;
  errorMessage$: Observable<string>;
  products$: Observable<Product[]>;
  selectedProduct$: Observable<Product>;

  constructor(private store: Store) { }

  ngOnInit(): void {
    this.store.dispatch(ProductPageActions.loadProducts());
    this.products$ = this.store.select(getProducts);
    this.errorMessage$ = this.store.select(getError);
    this.selectedProduct$ = this.store.select(getCurrentProduct);
    this.displayCode$ = this.store.select(getShowProductCode);
  }
}

So If we understand this, can initialize the code like the following. It saves your effor of explicit typing by using typescript type inference. and it also improves code readability.

@Component({
  //..
})
class ProductComponent {

  products$ = this.store.select(getProducts);
  errorMessage$ = this.store.select(getError);
  selectedProduct$ = this.store.select(getCurrentProduct);
  displayCode$ = this.store.select(getShowProductCode);

  constructor(private store: Store) { }
}

Please your library user with typescript generic

In typescript, generic is a tool that api/library author to please its consumer. What does this means.

For example, as library developer, I want to create a higher order function to modify a an existing function, so that I can log the entering and exiting of the function 's execution. The following function does the job

function log (fn) {
  const name = fn.name;
  return function (...args) {
    console.log(`entering ${name}`);
    const rtn = fn(...args);
    console.log(`leaving ${name}`);
  };
}

function add(a:number, b: number) {
  return a + b;
}

add(1, 2);
add('1', '2'); //warning
//
const logAdd = log(add); //type information is lost
logAdd(1, 2);
logAdd('1', '2'); //no warning

When consuming the log function, the modified function run as expected, but it lost the signature of the original function, and it cannot type checking like the original function.

It is pretty easy to solve the problem by adding generic to the log function.

function log<T extends (...args) => any>(fn: T) {
  const name = fn.name;
  return function (...args) {
    console.log(`entering ${name}`);
    const rtn = fn(...args);
    console.log(`leaving ${name}`);
  } as T;
}

function add(a:number, b: number) {
  return a + b;
}

add(1, 2);
add('1', '2'); //warning
//
const logAdd = log(add); //type information is retained.
logAdd(1, 2);
logAdd('1', '2'); //warning

Now the modified function has all the type information of the original function. The way it works is that typescript infer the type of input argument, and pass along the type along.

Class field initialization in typescript

In typescript class, you can define your field initialization in multiple ways. Here is one typical way to do that.

class BadPerson {

  fullName: string;
  age: number;
  created: Date;

  constructor(public firstName: string, public lastName: string) {
    this.fullName = this.firstName + ',' + this.lastName;
    this.age = 18;
    this.created = new Date();
    //
    //other imperative initailization goes to bottom
  }
}

//typescript will compile to javascript like 
class BadPerson {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.fullName = this.firstName + ',' + this.lastName;
        this.age = 18;
        this.created = new Date();
        //
        //other imperative initailization goes to bottom
    }
}

The problem here is that you have to explicitly have specify the types of each field, and you initialize them in different place from where they are declared. The better way to initialize class fileds is like the following.

class GoodPerson {

  fullName = this.firstName + ',' + this.lastName;
  age = 18;
  created = new Date();

  constructor(public firstName: string, public lastName: string) {
    //
    //other imperative initailization goes to bottom
  }
}
  
// typescript will compile to javascript like
class GoodPerson {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.fullName = this.firstName + ',' + this.lastName;
        this.age = 18;
        this.created = new Date();
        //
        //other imperative initailization goes to bottom
    }
}

Now the types of each fields are inferred correctly from the initialization, and you don't need to waste time to declare types from them. Secondly, you put initiaization and declaration in the same place, so the readability is much improved. Thirdly, the generated code is identical, so the logics is the same. It is true that field initialization happen before the code inside class constructor (from the code you can see that). So people believe that the shortcut field initialization in the constructor parameter is also initialized after normal field initialization, so if field initialization depends on the constructor parameter, they are not accessible. So people think they need to initialize those field inside the constructor. But from the compiled code, we can see that shortcut field initialization happens first, and they are accessible to other field initialization.

Apr 12, 2016

A JavaScript interview question which can be fixed by 'let'

A very popular JavaScript interview question on Lexical scope and closure is like the follow.

for (var i = 1; i < 6; i += 1) {
    //(function (i) {
 setTimeout(function() {
          console.log("I've waited " + i + " seconds!");
     }, 1000 * i);
    //})(i);
}

The code has a bug, that all the log output is the same, like the following.

Previously, to solve that is to uncommon the lines in previous code, because we can close the variable "i" in lexical scope using function. So that you can have something like

Now we have ES2016 or ES6, the new solution is actually very simple, just change "var" to "let". This is because let support block scope. In the loop block, the variable "let i" is private to the block. Every loop an new private scope is created. If you use transpiler such as typescript or babel, you can make it works in browser like IE10 or below and Safari 9. The transpilers are actually pretty smart, the following is transpiled by typescript, pretty impressive.

Aug 26, 2015

Minimize the price (not the benefit) of type in Typescript

I watched Anders Hejlsberg introducing typescript in 2012. Then I thought I don't have the problem it tries to solve. Type in Javascript has not yet caused any problem for me, as I have unit test, renaming and intellisense is also not a problem for me, because I have webstorm. Then, I found that Douglas Crockford said something in google plus

Microsoft's TypeScript may be the best of the many JavaScript front ends. It seems to generate the most attractive code. And I think it should take pressure off of the ECMAScript Standard for new features like type declarations and classes. Anders has shown that these can be provided nicely by a preprocessor, so there is no need to change the underlying language.

I think that JavaScript's loose typing is one of its best features and that type checking is way overrated. TypeScript adds sweetness, but at a price. It is not a price I am willing to pay.

I was kind of thinking the same way. So I didn't use Typescript in my all my projects until 4 months ago, when I joined a angularjs project where typescript is designated to be used. Now I feel that, type can be just a ceremony if it is not used properly, but it can be good enhancement of Javascript if used in the right way. In the following, I will list some of bad and good example of using typescript. The good examples can reduce the cost of using type without losing its benefit.

Don't annotate type for variable with value of built-in type, use inference.

//bad
var n: number = 7;
var s: string = 's';
var re: RegExp = /\s+/;
var itemsOfString: string[] = ['one', 'two', 'three'];

var callbacks: ((input: string) => number)[] = [
  function (a: string) {
    return Number(a);
  },
  function (b: string) {
    return Number(b);
  }];


//good, typescript can inference the type from value
var n = 7;
var s = 's';
var re = /\s+/;
var itemsOfString = ['one', 'two', 'three'];

var callbacks = [
  function (a: string) {
    return Number(a);
  },
  function (b: string) {
    return Number(b);
  }];

Use type annotation sparingly for custom type.

interface IPerson {
   firstName: string,
   lastName: string
}

function printPerson(person:IPerson) {
  console.log(person.firstName + ',' + person.lastName);
 }

//bad, this annotation is unnecessary
printPerson(<IPerson>{
 firstName: 'John',
  lastName: 'Doe'
});

//good, because the annotation can give you intellisense
var john: IPerson = {
  firstName: 'John',
  lastName: 'Doe'
};

printPerson(john);

//good, intellisense is available from inference
printPerson({
 firstName: 'John',
  lastName: 'Doe'
});

Don't create unnecessary interface or class if it is one-off thing, use inference

//bad, you need to duplicate type information from the object
interface Customer {
    firstName: string,
    lastName: string    
}
function createCustomer():Customer {
  return {
     firstName: 'John',
     lastName: 'Doe'
   };
}

//good, typescript compiler can infer the return type
function createCustomer(){
  return {
     firstName: 'John',
     lastName: 'Doe'
   };
}

Don't create interface if "named anonymous type" is available

//bad, you need to duplicate the type information from the object
namespace demo {
     
    export interface Settings {
          svcUrl: string
    }

    angular.module("demo").value("settings", {
         svcUrl: 'http://foo.com'
    });
}
//good
namespace demo {
    var settings = {
         svcUrl: 'http://foo.com'
    };

    export type Settings = typeof settings;
    angular.module("demo").value("settings", settings);
}
//
namespace demo {
    //use settings with type annotation 
    angular.module('demo').controller('main', function (settings: Settings) {
       console.log(settings.svcUrl);
    });
}

Don't create class if all you need is an interface, because typescript is using duck typing

//bad
class Customer {
    firstName: string;
    lastName: string ;
}

//good
interface Customer {
    firstName: string;
    lastName: string ;
}

function logCustomer(cust: Customer) {
   console.log(cust.firstName + ', ' + cust.lastName);
}

Don't use multiple assignment to define an object, use object literal expression

//bad, because typescript cannot infer the type of return object
function createCustomer () {
   var rtn : any = {};
   rtn.firstName = 'John';
   rtn.lastName = 'Doe';
   return rtn;
}

//good, because typescript can infer the literal object
function createCustomer () {
    return {
        firstName: 'John',
        lastName: 'Doe'
    }
}

Don't use module if it is internal module, use namespace

//bad 
module demo {

}

//good
namespace demo {

}

Don't use complicated construct, if simple construct is good enough

namespace demo {
    //bad
    export class Data {
        public static get key1(): string { return "value1"; }
        public static get key2(): string { return "value2"; }
    }

    //good
    export var data = {
        key1: 'value1',
        key2: 'value2',
    }
}

Aug 24, 2015

TypeScript is duck typing.

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

Typescript a superset of typescript, since Javascript is a duck typing language, typescript is also a duck typing language. In strong type languages the signature of an object is important and type is the signature of an object, they care about whether the signature are compatible. Typescript does not care about signature and type, cares about whether objects are replaceable because of what they can actually do.

Typescript interface is not a signature but semantics

Type compatibility in TypeScript is based on structural subtyping, it relates types based solely on their members. In the following example, variable foo and bar are declare of different interface type. The literal object can be assigned the variable foo, because typescript compiler can infer the ability of the literal object(this is called type inference), and typescript compiler think that literal object can do what interface is expected to do. And foo can be assigned to bar, because foo can do what interface Bar is expected to do. The name of interface (Foo and Bar) does not matter, what is matter is semantics of the interface.

//--interface is semantics
interface Foo {
  quack();
}

interface Bar {
  quack();
}

var foo : Foo;
var bar: Bar;

foo = {
   quack: function () {}
};

bar = foo;

Typescript class is just an interface with implementation

One of the reason that people use Typescript is that it support class. However, typescript class is different from C# and Java class. The following are similar to Java class. You can create an instance of a class by using the keyword "new", you can inherit a class by using keyword "extends".

//--class as implementation
class Duck {
    constructor(public name: string) {
    }
    quack() {
        console.log('Duck quack ' + this.name);
    }
}

class Swan extends Duck {
    fly() {
        console.log('Swan fly ' + this.name);
    }
}

var duck = new Duck('duck1');
duck.quack();
//
var swan = new Swan('swan1');
swan.quack();
swan.fly();

But a less well-known fact is that typescript class can be used as an interface, like the following code

//---class as interface----
var objectOfAnounymousType = {
    name: 'Daisy',
    quack: function () {
        console.log('quack quack ' + this.name);
    }
};
var daisy: Duck = objectOfAnounymousType;
daisy.quack();

class Person implements Duck {
    name = "Person"
    quack() {
        console.log('Person quack ' + this.name);
    }
}

var john = new Person();
john.quack();

daisy = john;
daisy.quack();

When typescript compiler see the a literal object, it can infer an anonymous type from the object. When the object is assigned to a variable of Duck class, typescript compiler find that the anonymous type is compatible to Duck class(interface) because the anonymous type has all the members that Duck class has. The class Person does not extend (inherit) Duck class, instead it treat Duck class as an interface, and implements it.

The difference between interface and class is that interface does not has implementation but class has implementation. Because of this, class can implement interface, but interface can not implement interface.

interface IDuck {
    name: string,
    quack: () => void
}

interface ISwan extends IDuck {
    fly(): void
    
}

class Duckling implements IDuck {
   constructor(public name: string) {
    }
    quack() {
        console.log('Duckling quack ' + this.name);
    }
}

Thanks for taking the time to read this. Feedback, critiques and suggestions are welcomed.

Aug 20, 2015

Leave $rootScope alone, use AngularJs Dependency Injection.

AngularJs brings dependency injection into UI development. It works very well until it is misused. Recently, I was working on an AngularJs project. One interesting thing is that some application settings is attached to $rootScope for convenient consumption. When I saw it, I felt this was so Déjà vu. The $rootScope has essentially become the new "window" object in the browser, where all global variables can be attached to. So I Googled about this and wanted to know whether other people have similar problem, and I found this question in StackOverflow, Global variables in AngularJS. It seems that this is a quite a common problem out there. So I wanted dig into it more.

In the article Global Variables Are Bad, a few bad reasons were listed for using global variables.

  1. "What's a 'local variable'?"
  2. "What's a 'data member'?"
  3. "I'm a slow typist. Globals save me keystrokes."
  4. "I don't want to pass it around all the time."
  5. "I'm not sure in what class this data belongs, so I'll make it global."

I think the the reason we want to attach variables to $rootScope is because of #3 and #4 of the reason above. I don't need to argue why Global variables are bad, because the article has very good coverage. But in case of AngularJs, by changing the dependency on "setting" to "$rootScope.setting", the dependencies of "setting" become implicit. This is bad for communication, documentation, and maintenance. And it will encourage dumping more dependencies into $rootScope. The advantage of AngularJs dependency injection is completely gone. Explicit dependencies become exploring dependencies in the dark world of $rootScope.

One more possible reason in using $rootScope is that it makes the databinding easier, because all child scopes will inherit $rootScope's properties. But this only works when the child scope is not isolated scope. This practice will discourage the use of isolated scope, which is a great way to improve reusability of your directive.

Using inheritance from parent scope and $rootScope is very fragile and heavy coupling. A better way is to use dependency injection. Let's see an example, which is over-simplified. It may violate the best practice of AngularJs you have learned from somewhere else. But the point is to demonstrate the difference between using global variable and dependencies injection.

So the demo app wants to show a user a login screen if the user is not logged in, otherwise a welcome screen. Simple enough. The following is the implementation using global variable. You can see the code at http://output.jsbin.com/monozu. This implementation creates a global variable attached to $rootScope, which is visible to child scopes.

  <div ng-controller="login">
    <div  ng-if='!user.isAuthenticated'>
      You are not logged in yet.
      <button ng-click="user.login()">
        Log in
      </button>
    </div>
  </div>
  
  <div ng-controller="welcome" >
   <div ng-if='user.isAuthenticated'>
      Hello, {{user.firstName + ',' +  user.lastName}}
    </div>
  </div>
  var app = angular.module('app', []);
  
  app.run(function ($rootScope) {
    $rootScope.user = {
      isAuthenitcated: false,
      login: function () {
        this.firstName = 'John';
        this.lastName = 'Doe';
        this.isAuthenticated = true;
      }
    };
  });

app.controller('login', function ($scope) {

  });
  
  
  app.controller('welcome', function ($scope) {

  });

The following is the implementation using dependency injection. You can see the code at http://output.jsbin.com/senuti. The html template is still the same, but in JavaScript, the user global variable is removed from $rootScope, and become a service, which is injected into to each controller.

  app.factory('user', function () {
    return {
      isAuthenticated: false,
      login: function () {
        this.firstName = 'John';
        this.lastName = 'Doe';
        this.isAuthenticated = true;
      }
    };
  });
  

  app.controller('login', function ($scope, user) {
    $scope.user = user;
  });
  
  
  app.controller('welcome', function ($scope, user) {
    $scope.user = user;
  });

The implementation using dependency injection may use a little more code, but is more testable, maintainable and scalable. Please comment and let know what you think.