TypeScript Notes: Part 1


I decided to post a series of notes on TypeScript and this is Part 1.  I think understanding what TypeScript does makes you a better JavaScript programmer as you will come to know the issues inherent in JavaScript.  The format I will be using is to present the TypeScript code and explain it along the way in the comments itself and then present the generated JavaScript code.  You can play with the code by copying it and pasting it on any online TypeScript compiler/runner app.  I recommend Playground TypeScript.  So let’s get to it and no more dilly dally.

// TypeScript Notes: Part 1

// Using var
// Works almost the same way as using var in Javascript
var myDeclaredVar = "Rodan Sotto";
console.log(myDeclaredVar); // displays "Rodan Sotto"
//console.log(myUndeclaredVar); // compile-time error; in JavaScript it's a runtime error
console.log(myHoistedVar); // displays "undefined"; no error because all JavaScript var declarations anywhere in the code are moved up and made available from line 1 (concept called hoisting)
var myHoistedVar = 5;

var myNoBlockLevelScopingVar = 5;
if (myNoBlockLevelScopingVar > 2) {
    var myNoBlockLevelScopingVar = 6;
    console.log(myNoBlockLevelScopingVar); // displays 6 as expected
}
console.log(myNoBlockLevelScopingVar); // displays 6 as well because JavaScript var declarations don't have block level scoping


// Using let
// This solves issues with variable hoisting and no block level scoping
let myLetVar = "Rodan Sotto";
console.log(myLetVar);
console.log(myNotHoistedLetVar); // compile-time error because let does not allow hoisting variables
let myNotHoistedLetVar;

let myBlockLevelScopingLetVar = 5;
if (myBlockLevelScopingLetVar > 2) {
    let myBlockLevelScopingLetVar = 6;
    console.log(myBlockLevelScopingLetVar); // displays 6 as expected
}
console.log(myBlockLevelScopingLetVar) // displays 5 because let allows block level scoping (check the generated JavaScript code how it does this)


// Using const
const myConst = 5;
myConst = 6; // compile-time error because const does not allow changing the values of constant or read-only variables


// Data types: number, string, and boolean
let n: number = 123;
let s: string = "ABC";
let b: boolean = true;
n = "DEF"; // compile-time error because TypeScript is type safe
s = 456; // compile-time error
b = "GHI"; // compile-time error

let myTypeInferedVar = 1;
myTypeInferedVar = "A"; // compile-time error because TypeScript has type inference that decides the type of datatype-less variables based on first assignment

let myNotTypeInferedVar; // notice that there is no initialization here
myNotTypeInferedVar = 1;
console.log(myNotTypeInferedVar); // displays 1
myNotTypeInferedVar = "A";
console.log(myNotTypeInferedVar); // displays "A"; no compile-time error because varialbles with no data type specified is by default has an implicit datatype of any

// Data type any
// This is default datatype for datatype-less variables
// Use it when it is a must because it is not a best practice always.
let myAnyTypeVar: any;
myAnyTypeVar = 1;
console.log(myAnyTypeVar); // displays 1
myAnyTypeVar = "A";
console.log(myAnyTypeVar); // displays "A"


// Generic arrays
// Just like the C# generic collection
let myNumberArray: Array<number> = new Array<number>();
myNumberArray.push(1);
myNumberArray.push(2);
myNumberArray.push("C"); // compile-time error


// Functions in TypeScript ...
// ... forces you to return
function myNumberFunction(): number {
    return 1; // without this return statement will produce compile-time error
}

// but following function declarations will not force you to return
function myVoidFunction(): void { } // you cannot have return statement here
// or
function myAnyFunction(): any { } // you can have return statement here
// or
function myFunction() { } // by default the return type is any

// ... has parameter checking
function myFunctionWithParams(x: number, y: number): void {
    console.log(x + y);
}
myFunctionWithParams(1, 2);
myFunctionWithParams(1, 2, 3); // compile-time error

// ... does not allow duplicate function names regardless if parameters are different
function myDuplicateFunction(x: number, y: number): void { }
function myDuplicateFunction(x: number, s: string, b: boolean): void { } // compile-time error

// ... has optional parameters
function myFunctionWithOptionalParams(x: number, y?: number): void {
    console.log(x);
    console.log(y);
}
myFunctionWithOptionalParams(1, 2); // displays 1 and 2
myFunctionWithOptionalParams(1); // displays 1 and "undefined"

// ... hs rest parameter which allows defining function with array as parameters
function myFunctionWithRestParam(...x: Array<number>): void {
    for (let e of x) {
        console.log(e);
    }
}





myFunctionWithRestParam(1, 2); // displays 1 and 2
myFunctionWithRestParam(3, 4, 5); // displays 3, 4, and 5
myFunctionWithRestParam(6, 7, 8, 9, 0); // displays 6, 7, 8, 9, and 0

// Generated JavaScript Code From TypeScript Notes: Part 1



var myDeclaredVar = "Rodan Sotto";
console.log(myDeclaredVar); // displays "Rodan Sotto"
//console.log(myUndeclaredVar); // runtime error
console.log(myHoistedVar); // displays "undefined"
var myHoistedVar = 5;

var myNoBlockLevelScopingVar = 5;
if (myNoBlockLevelScopingVar > 2) {
    var myNoBlockLevelScopingVar = 6;
    console.log(myNoBlockLevelScopingVar); // displays 6 as expected
}
console.log(myNoBlockLevelScopingVar); // displays 6 as well




var myLetVar = "Rodan Sotto";
console.log(myLetVar);
console.log(myNotHoistedLetVar);
var myNotHoistedLetVar;

var myBlockLevelScopingLetVar = 5;
if (myBlockLevelScopingLetVar > 2) {
    var myBlockLevelScopingLetVar_1 = 6;
    console.log(myBlockLevelScopingLetVar_1); // displays 6 as expected
}
console.log(myBlockLevelScopingLetVar); // displays 5



var myConst = 5;
myConst = 6;


// Data types: number, string, and boolean
var n = 123;
var s = "ABC";
var b = true;
n = "DEF";
s = 456;
b = "GHI";

var myTypeInferedVar = 1;
myTypeInferedVar = "A";

var myNotTypeInferedVar;
myNotTypeInferedVar = 1;
console.log(myNotTypeInferedVar); // displays 1
myNotTypeInferedVar = "A";
console.log(myNotTypeInferedVar); // displays "A"




var myAnyTypeVar;
myAnyTypeVar = 1;
console.log(myAnyTypeVar); // displays 1
myAnyTypeVar = "A";
console.log(myAnyTypeVar); // displays "A"




var myNumberArray = new Array();
myNumberArray.push(1);
myNumberArray.push(2);
myNumberArray.push("C");




function myNumberFunction() {
    return 1;
}


function myVoidFunction() { }

function myAnyFunction() { }

function myFunction() { }


function myFunctionWithParams(x, y) {
    console.log(x + y);
}
myFunctionWithParams(1, 2);
myFunctionWithParams(1, 2, 3);


function myDuplicateFunction(x, y) { }
function myDuplicateFunction(x, s, b) { }


function myFunctionWithOptionalParams(x, y) {
    console.log(x);
    console.log(y);
}
myFunctionWithOptionalParams(1, 2); // displays 1 and 2
myFunctionWithOptionalParams(1); // displays 1 and "undefined"


function myFunctionWithRestParam() {
    var x = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        x[_i - 0] = arguments[_i];
    }
    for (var _a = 0, x_1 = x; _a < x_1.length; _a++) {
        var e = x_1[_a];
        console.log(e);
    }
}
myFunctionWithRestParam(1, 2); // displays 1 and 2
myFunctionWithRestParam(3, 4, 5); // displays 3, 4, and 5
myFunctionWithRestParam(6, 7, 8, 9, 0); // displays 6, 7, 8, 9, and 0

Advertisements

JavaScript: You think you know it well?

Just because you are a C# or Java developer that you think you know JavaScript well.  Well I don’t.  But no worries, below are some quick pointers to remember:

  • null and undefined are types, just like Numbers, Strings, Booleans, and Objects.  null indicates a deliberate non-value while undefined indicates an uninitialized value.
  • Primitive/literal values (null, undefined, “string”, 10, true, false) are converted to objects (wrapper objects) when properties are accessed.
  • Functions and Arrays are special types of objects.
  • Built in Error types are there as well.
  • Object(), Array(), String(), Number(), Boolean(), Function(), Date(), RegExp(), and Error() are native constructor functions.
  • parseInt() and parseFloat() parse the number in string until it reaches an invalid character.
  • Unary + operator converts values to numbers (+ “42” = 42 ) and returns NaN (Not a Number) if non-numeric.
  • isNaN() tests for NaN.
  • isFinite() tests for Infinity (1/0), -Infinity (-1/0), and NaN.
  • false, 0, empty string (“” ), NaN, null, and undefined convert to false, and all others convert to true.
  • Blocks do not have scope, only functions have scope.
  • “3” + 4 + 5 = 345, while 3 + 4 + “5” = 75.
  • Triple-equals operator avoids type coercion.  1 === true is false, but true === true is true.
  • JavaScript objects are simple collections of name-value pairs where the name is a JavaScript string and the value is any JavaScript value.
  • array.length isn’t necessarily the number of items in the array.  It is one more than the highest index.
  • No return statement or empty return with no value in a function returns undefined.
  • arguments variable contains all the values passed to the function.
  • IIFEs (Immediately Invoked Function Expressions) is basically what it says.  It’s a function in an expression and invoked immediately ( (function () { … })();  )
  • To call functions recursively, you can use a named IIFE ( (function myFunc() { myFunc(); })();  ).  The name is only available to the function’s own scope.
  • this inside a function refers to the current object if the function is called against an object or using dot notation or bracket notation; otherwise it will refer to the global object.
  • Global object or the head object in JavaScript in a web browser environment is the window object.  Variables you declare globally in your JavaScript code will become properties of the window object.
  • JavaScript does not have classes; it only has object prototypes. It uses functions as classes.  You declare the properties inside the function and declare the methods by assigning them to the function object’s prototype.
  • prototype is an object shared by all instances of the object.  It forms part of a lookup chain, which has a special name called prototype chain.  Anything assigned to the object’s prototype becomes available to all instances of the object.
  • Inner or nested functions can access variables in their parent function’s scope.
  • Closure happens when an outer function returns the inner function and the inner function needs access to the outer function’s local variables.  The outer function’s scope object is actually retained even after the outer function has returned.  Only when there are no more references to the inner function will the outer function’s scope object be garbage collected.
  • Scope objects form a chain called the scope chain.  Scope object is created every time the function starts executing.

JavaScript: Attaching/Detaching Event, OnLoad vs. DOMContentLoaded, Manipulating DOM and CSS

Event Handling, Attaching and Detaching Events

3 phases of event dispatch:

  • Capturing – going down the DOM tree until it reaches the target element
  • Target
  • Bubbling – going back up the DOM tree from the target element

 

// standard way of accessing the Event object
var eventHandlerDOM = function(evt) {
alert(evt.type); //displays click
}

// starting IE 9 you can use the standard way
var eventHandlerIE8Older = function() {
var evt = window.event;
alert(evt.type);
}

// cross-browser way
var eventHandlerCB = function(evt) {
if (!evt) evt = window.event;
alert(evt.type);
}

window.onload = function() {
var btn = document.getElementById("btn");

// 2 ways of attaching an event
btn.onclick = eventHandlerCB;
// or ...
if (btn.addEventListener) {
btn.addEventListener("click", eventHandlerCB, false);
}
else {
// starting IE 9, you can use the standard way using
// addEventListener
btn.attachEvent("onclick", eventHandlerCB);
}

alert("events attached");
alert("now detaching events...");
detachEvents();
alert("events detached");
}

// detaching events
var detachEvents = function() {
if (btn.removeEventListener) {
btn.removeEventListener("click", eventHandlerCB, false);
}
else {
// starting IE 9, you can use the standard way using
// removeEventListener
btn.detachEvent("onclick", eventHandlerCB);
}
}

 

window.onload Event vs. document.DOMContentLoaded event

The problem with running script on window.onload event is that if you have a rather large image to download, your script will run only after the image is downloaded.  window.onload event is triggered after everything, including external stylesheets, javascript files and images, has been downloaded.  An alternative, and usually a best practice, is to run your script on document.DOMContentLoaded event.

var readyFunc = function() {
var stat = document.getElementById("statDOMReady");
stat.innerHTML = "DOM is ready!!!";
}

document.addEventListener("DOMContentLoaded", readyFunc, false);

 

Note that document.DOMContentLoaded event is an HTML5 specification.  Also if your script needs to work with CSS, you need to put all your external stylesheets in the header and all your external scripts in the footer so all the styles will be loaded before your scripts are run.

 

Manipulating DOM

A sample of what you can do for manipulating DOM:

  • document.createElement() – create an Element node
  • document.createTextNode() –  create a Text node
  • element.cloneNode() – create a copy of a node and its attributes with option to include the descendants as well
  • element.appendChild() – add a new child node as the last child node
  • element.insertBefore() – insert a new child node before a specified child node
  • element.removeChild() – remove a child node
  • element.replaceChild() – replace a child node
  • document.createDocumentFragment() – create an imaginary Node object; useful for adding content to your document, or extracting parts of your document and modifying it and inserting it back

 

Manipulating CSS

2 ways to import external stylesheets:

<!-- using <style> tag and @import -->
<style type="text/css">
@import "myStylesheet.css";
</style>

<!-- using <link> tag and rel="stylesheet" -->
<link type="text/css" href="myStylesheet.css" rel="stylesheet" />


 

Persistent, preferred, and alternate stylesheets:

<!-- persistent stylesheet -->
<link type="text/css" href="main.css" rel="stylesheet" />

<!-- preferred stylesheet -->
<link type="text/css" href="dflt.css" rel="stylesheet" title="Default" />

<!-- alternate stylesheet -->
<link type="text/css" href="alt1.css" rel="alternate stylesheet"
title="Alternate 1" />

 

element.style, window.getComputedSyle(), element.currentStyle, elements positioning properties:

var p1 = document.getElementById("p1");
p1.style.fontSize = "20px";

// standard way of getting the computed style
var computedStyle = window.getComputedStyle(p1, null);
alert(computedStyle.fontSize); // displays 20px

// IE way of getting the computed syle
// starting from IE9, you can use the standard way
var computedStyle2 = p1.currentStyle;
alert(computedStyle2.fontSize); // displays 20px

// cross-browser code for getting the computed style
if ( !("getComputedStyle" in window) ) {
alert("getComputedStyle does not exist")
window.getComputedStyle = function(element) {
return element.currentStyle;
}
}

// positioning properties of an element you can use
alert(p1.offsetTop); // displays 130
alert(p1.offsetLeft); // displays 8
alert(p1.offsetHeight); // displays 23
alert(p1.offsetWidth); // displays 911
// below will display 0, because it's parent is the body tag
alert(p1.offsetParent.offsetTop);
var body = document.getElementsByTagName("body")[0];
alert(body.offsetTop); // displays 0

JavaScript: RegExp, Error, DOM, and Event

This post is a follow-up to my previous posts, Object Oriented Programming In Javascript and JavaScript Array and How It’s Different from Object.  In this post I will touch on regular expressions, error handling, basic DOM scripting, image preloading, and timing events.

 

Regular Expressions

// creating patterns
var pattern1 = new RegExp("Rodan"); // using constructor
var pattern2 = /Rodan/; // using literal enclosed in "/"

// testing strings against the patterns
alert(pattern1.test("Rodan Sotto")); // displays true
alert(pattern2.test("John Doe")); // displays false

// using String methods search, match, and replace with regular expressions
var string1 = "Rodan Sotto";
var string2 = "John Doe";

// below will display 6, the starting position of the substring found
alert(string1.search(/Sotto/));
// below will display -1, which means no substring found
alert(string2.search(/Sotto/));

alert(string1.match(/Sotto/)); // displays an array ["Sotto"]
alert(string2.match(/Sotto/)); // displays null

// below will display "Rodan Nolastname"
alert(string1.replace(/Sotto/, "Nolastname"));
// below will display "John Doe"
alert(string2.replace(/Sotto/, "Nolastname"));

See JavaScript RegExp Object for more information.

 

Error Handling

var testErrorHandling = function () {
try {
alert("Throwing an error inside the try block...");
throw(new Error("You've got an error!!!"));
}
catch (error) {
alert(error.message);
}
finally {
alert("Error or not, finally will get executed");
}
};

 

Basic DOM Scripting

W3Schools.com has a very good beginner resource on HTML DOM.

  • DOM stands for Document Object Model.  Everything in DOM is a node.  A Node can be any of the following:
    • Document Node
    • Element Node
    • Attribute Node
    • Text Node
    • Comment Node
  • Document Object, which represents your web page, is the first object you will need to access the DOM.  It is the root node of the HTML document and the owner of all other nodes.  See Document Object Properties and Methods.
  • Element Object, which represents an HTML element, is the second object you will need to access the DOM.  Most commonly a call to document.getElementById() method will return an element object.  An element object is also an element node.  It can have child nodes such as element nodes, attribute nodes, text nodes, or comment nodes.  See Element Object Properties and Methods.
  • An Element Object can be one of the following:
    • Anchor Object
    • Image Object
    • Button Object
    • etc., each of which can have it’s own set of properties and method.
  • And lastly, the Attr Object which represents an HTML attribute and always belongs to an HTML element.  See Attr Object Properties and Methods.
  • Events.  See HTML DOM Events.  It lists the different events such as:
    • Mouse Events
    • Keyboard Events
    • Frame/Object Events
    • Form Events
    • It also lists the properties and methods of event objects that event handlers have access to such as:
      • Event Object
      • EventTarget Object
      • EventListener Object
      • DocumentEvent Object
      • MouseEvent Object
      • KeyboardEvent Object

 

Default Action Cancellation

var event_handler = function(evt) {
if (!evt) evt = window.event; // for IE

// ...

// cancel default action
if (evt.preventDefault) {
evt.preventDefault(); // for most browsers
}
else {
evt.returnValue = false; // for IE
}
}

window.onload = function() {
var link = document.getElementById("link");
link.onclick = event_handler;
}

 

Image Preloading

var image = new Image();
image.src = "image.jpg";
// or
image.src = link.href;

 

Timing Events

JavaScript also provides for executing code at specific time-intervals using setInterval() and setTimeout() methods.  See JavaScript Timing Events.  

So what is Closure?

I’m not talking about closure in a relationship :).  I am talking about closure in programming.  I first encountered closure in JavaScript the hard way.  I was debugging for days the following code as to why it was not behaving the way I expect it to be.

var setRowsOnclickEvent = function () {
    var table = $("tableList");
    
    for (var i = 1; i < table.rows.length; i++) {
        var row = table.rows[i];
        
        row.onclick = function () {
            var table = $("tableList");
            
            for (var j = 1; j < table.rows.length; j++) {
                var row = table.rows[j];
                
                if (j == i) {
                    row.className = "selectRow";
                }
                else {
                    row.className = "unselectRow";
                }
            }
        }
    }
}

 

 

The JavaScript function above is setting the onclick event of all the rows in the table.  It iterates through each row in the table and assigns an inline function, an event handler, to the row’s onclick event.  Note that the event handler, or the inner function, uses the loop variable i of the outer function, containing the row number, so that whenever the row is clicked it get’s highlighted.

My mistake was to think that the value of i is passed on to the event handler like a function parameter and placed on the stack.  Don’t make that mistake. The value of i actually closes on you, I mean on the event handler, or the inner function.  So variable i is a closure variable, while the inner function is a closure function.

Again don’t make the mistake that assigning the event handler to the onclick event actually calls the event handler.  It’s an event handler so it can be called even after the outer function has been out of scope.

So you ask, what happens to the value of i then? Well for closure situations like this, the compiler creates a special context object containing the closure variables so that closure functions, when they get executed, will have access to these variables even if the function that the closure variables are declared in are already out of scope.

In the above JavaScript code, what’s happening is whenever any row is clicked, the last row always gets highlighted, so which is to say, the variable i always has the value of the last row number.  The reason is because, again, even if the closure function, or the event handler in our example, is inside a loop that iterates through each row and incrementing the closure variable i, when the loop exits, the closure variable i will contain the last value in the loop which is the last row number and that is the value that the event handler will get when it gets executed at a later time.  So the value of the closure variable i will be the value at runtime and not at capture time, or in our example, not at the time when the event handler is declared and assigned.

Below is my solution to the JavaScript code above.  The solution is to wrap the event handler in another function where I pass in i as a function parameter, thereby forcing the compiler to capture the value of i as it increments itself inside the loop.

var setRowsOnclickEvent = function () {
    var table = $("tableList");
    
    for (var i = 1; i < table.rows.length; i++) {
        var row = table.rows[i];
        
        row.onclick = (function (i) {
            return function () {
                var table = $("tableList");
                
                for (var j = 1; j < table.rows.length; j++) {
                    var row = table.rows[j];
                    
                    if (j == i) {
                        row.className = "selectRow";
                    }
                    else {
                        row.className = "unselectRow";
                    }
                }
            }           
        })(i);
    }
}

 

 

EDIT:  The code above works by making the function (outer function) that wraps the event handler (inner function) as an IIFE (Immediately Invoked Function Expressions).  This creates a scope object for the outer function (remember Javascript scoping stops at the function level while C# continues at the block level) containing the current value of i in the loop which is retained even after the outer function has returned.  Then each row’s onclick event will end up having an inner function with access to a separate outer function’s scope object, each containing a different value of i.

It’s not only the JavaScript language that has closure.  Other languages have it as well, like C#.  I encountered closure in C# the same way I did in JavaScript.  I was declaring/passing in a lambda expression to a function call inside a foreach loop, that references the foreach variable.  And since C# has a slightly different handling of closure than JavaScript, the solution is different.  In C#, one just need to assign the foreach or loop variable to a temporary variable and reference the temporary variable instead.

public void SomeFunction()
{
    // ...
    foreach (Filter filter in filters)
    {
        // have to assign filter value to temp variable in the loop
        //  because the lambda expression we're using here is in a closure
        string filterVal = filter.Value;
        switch (filter.Field)
        {
            case "Location Name":
                locs = locs.Where(l => l.LocationName.Contains(filterVal));
                break;
            // ...
        }
    }
    // ...
}

 

 

It’s not easy to wrap your mind around closure, at least for me.  Closures in C# vs JavaScript – Same But Different really explains it to me clearly, from a really really technical point of view, as in how the compiler handles closure both in C# and JavaScript.  Don’t worry it’s not a long read but one needs to really read through the code. I’ve got other links for further reading if need be:

I can’t guarantee you to become a closure relationship expert, but after going through the readings and links above,  I can guarantee you to become a closure programming expert ;).