Category Archives: TypeScript

TYPESCRIPT 3 BRUSH UPDATE

I decided to update my TypeScript brush plugin for TypeScript 3.0 and also to specify it works with latest WordPress 4.9.8.  The plugin page on WordPress.org is located here – https://wordpress.org/plugins/syntax-highlighter-evolved-typescript/changelog/

Samples (from here and here)


let foo: unknown = 10;

// Since `foo` has type `unknown`, TypeScript
// errors on each of these locations.
foo.x.prop;
foo.y.prop;
foo.z.prop;
foo();
new foo();
upperCase(foo);
foo `hello world!`;

function upperCase(x: string) {
return x.toUpperCase();
}


// TODO (billg): 5 overloads should *probably* be enough for anybody?
function call<T1, T2, T3, T4, R>(fn: (param1: T1, param2: T2, param3: T3, param4: T4) => R, param1: T1, param2: T2, param3: T3, param4: T4): R
function call<T1, T2, T3, R>(fn: (param1: T1, param2: T2, param3: T3) => R, param1: T1, param2: T2, param3: T3): R
function call<T1, T2, R>(fn: (param1: T1, param2: T2) => R, param1: T1, param2: T2): R
function call<T1, R>(fn: (param1: T1) => R, param1: T1): R;
function call<R>(fn: () => R, param1: T1): R;
function call(fn: (...args: any[]) => any, ...args: any[]) {
return fn(...args);
}


export interface Props { name?: string }
export class Greet extends React.Component<Props> {
render() {
const { name } = this.props;

// Notice the `!` ------v
return <div>Hello ${name!.toUpperCase()}!</div>;
}
static defaultProps = { name: "world"}
}


function loudlyGreet(name = "world") {
// Thanks to the default initializer, `name` will always have type `string` internally.
// We don't have to check for `undefined` here.
console.log("HELLO", name.toUpperCase());
}

// Externally, `name` is optional, and we can potentially pass `undefined` or omit it entirely.
loudlyGreet();
loudlyGreet(undefined);


// Some non-TypeScript JSX file

import * as React from "react";
import * as ReactDOM from "react-dom";

export class Greet extends React.Component {
render() {
const { name } = this.props;
return <div>Hello ${name.toUpperCase()}!</div>;
}

static defaultProps = {
name: "world",
};
}

// Notice no `name` attribute was specified!
// vvvvvvvvv
const result = ReactDOM.renderToString(<Greet />);
console.log(result);


import * as _foo from "foo";

export async function bar() {
let foo: typeof _foo = await import("foo");
}



function useKey<T, K extends Extract<keyof T, string>>(obj: T, k: K) {
let propName: string = k;
// ...
}

Test of Typescript SyntaxHilighter 1.5

 

//#region person class
class Person {
  @memoize('test')  //Typescript 1.5 decorators
  get name() { return '${this.first} ${this.last}'; }
  //test
  set name(val) {
    let [first, last] = val.split(' ');
    this.first = first;
    this.last = last;
  }
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  //test of comment with a > and a < in it. Plus a #. Plus @test2
  greet(@anotherDecorator z : string) : string {
    var x = greeting || test;
    var t = 12 + 3;
    var b = !!x;
    $(".js-alert-link").on("click", (event:JQueryEventObject) => this.startTimer(event));
    return "Hello, " + this.greeting;
  }
}
//#endregion


TYPESCRIPT CONVERSION A MONTH LATER

I’d like to report that the port of my project to TypeScript has been a success, so far the issues encountered have been minimal.  One issue I did bump into recently was due to a typo on my part.  I had used a variable in a small method as both a string and number at different points, like so

var x = parseInt(somestring);

...

x = x.toString();

During the conversion to TypeScript, I resolved the type errors caused by this by creating a string and a numeric variable like so

var xn : number = parseInt(somestring);

...

var xs:string = xs.toString();

but notice the typo, I did xs.toString() and assigned it to xs itself, not xn.toString().  This does not cause any compilation errors in TypeScript, but the code is essentially a guaranteed null reference error at run-time.  In my case it was a month before the little used method was executed.

TYPESCRIPT WORDPRESS PLUGIN FOR SYNTAX HIGHLIGHTER EVOLVED

I developed a simple WordPress Plugin for Syntax Higlighter Evolved for displaying TypeScript (http://wordpress.org/plugins/syntax-highlighter-evolved-typescript/)

I found these links helpful in publishing and deploying the plugin. 

First I signed up as suggested here (https://wordpress.org/plugins/about/) and then I got the relevant SVN information via e-mail.

Afterwards, I used TortoiseSVN as described here (http://eamann.com/tech/how-to-publish-a-wordpress-plugin-subversion/) and deployed.

TYPESCRIPT CONVERSION TAKEAWAY

The conversion of the 20,000 lines of legacy Javascript in the Windows Control Library was a success.  I touched on the major issues in my previous posts.   The issues encountered themselves weren’t any kind of flaw in TypeScript,  it just demonstrated the need to keep in mind the style of Javascript code that is being generated.  After going through the experience, the following steps are what I would recommend for TypeScript conversion:

1) Rename your .js (Javascript) files to .ts (TypeScript) files and compile.  Fix all errors that arise and test your fixes.

2) Add type annotations to all variable and parameter declarations.  Minimize the use of the ‘any’ type.  Add interfaces to define function signatures.  Use interfaces to describe existing data structures.  Don’t refactor any of your code yet, wait until conversion is complete.

3) Restructure your JavaScript code into modules and classes.  I myself did Step 3 before Step 2, but if I did it again I would do Step 2 first.

TYPOS IN TYPESCRIPT

One problem I encountered was when I made a typo while converting a prototypical class and I was chopping the  “class.prototype’ out of the function declarations and replacing it with the private or public keyword.  For example a class like so

var MyNamespace = MyNamespace || {};

MyNamespace.Widget2 = function(inp,a,b)
{
	this._a = a;
	this._b = b;
	this._inp = inp;
}

MyNamespace.Widget2.prototype.create = function()
{
	this.click();
}

MyNamespace.Widget2.prototype.method1 = function(x)
{
	alert('hello');
}

MyNamespace.Widget2.prototype.click = function(e)
{
	this.method1();
}

Was converted to

module MyNamespace
{
	export class Widget2
	{
		private _a : number;
		private _b : number;
		private _inp : number;

		constructor (inp,a,b)
		{
			this._a = a;
			this._b = b;
			this._inp = inp;
		}

		public create()
		{
			this.click();
		}


		public method1(x)
		{
			alert("hello");
		}

		public click = function()
		{
			this.method1();
		}

	}
}

Note what I consider the typo – the click function was not completely converted, I forgot to strip the ‘= function’  and now it is an assignment to a variable, but it is perfectly valid TypeScript.  and it will run correctly. The problem is ‘this’ in the function is not typed as Widget2 but as ‘any’. Now the code will run fine BUT if you make any modifications to the use of ‘this’ in the function you will not get the protections afforded by TypeScript – for example the following class will compile perfectly fine due to ‘this’ being typed as ‘any’, and fail at runtime.

module MyNamespace
{
	export class Widget2
	{
		private _a : number;
		private _b : number;
		private _inp : number;

		constructor (inp,a,b)
		{
			this._a = a;
			this._b = b;
			this._inp = inp;
		}

		public create()
		{
			this.click();
		}


		public method1(x)
		{
			alert("hello");
		}

		public click = function()
		{
                        // method name incorrect 
			this.mthod1();			
		}

	}
}

The recommendation I have for this situation if you are converting a large codebase is to do a regex search in Visual Studio on

(public|private)?s+($|w|_)+s+=s+function

And see if you have made the mistake yourself. If you use unicode characters in your identifiers you will have to update the regex

THIS AGAIN

Another issue I bumped into was converting closures to TypeScript classes, ‘this’ again popped up as part of a larger issue.  For example, starting with the following Javascript code

var MyNamespace = MyNamespace || {};

MyNamespace.Widget1 = function(inp,a,b)
{
	var _a = a;
	var _b = b;
	var _inp = inp;

	this.create = function() 
	{
		inp.addEventListener("keydown",this.click);

	}

	this.click = function(e)
	{
		alert("clicked " + _a);
	}

}

I converted it to the following TypeScript.

module MyNamespace
{

	export class Widget1
	{
		private inp : HTMLElement;
		private _a : number;
		private _b : number;
		
		constructor(inp:HTMLElement,a:number,b:number)
		{
			this._a = a;
			this._b = b;
			this.inp = inp;
		}

		public create() 
		{
			this.inp.addEventListener("keydown",this.click);

		}

		private click(e)
		{
			alert("clicked " + this._a);
		}

	}


}

But this has a problem,  I’ve converted a closure style object to a prototype style (what a TypeScript class is converted to) as can be seen here in the generated Javascript:

var MyNamespace;
(function (MyNamespace) {
    var Widget1 = (function () {
        function Widget1(inp, a, b) {
            this._a = a;
            this._b = b;
            this.inp = inp;
        }
        Widget1.prototype.create = function () {
            this.inp.addEventListener("keydown", this.click);
        };

        Widget1.prototype.click = function (e) {
            alert("clicked " + this._a);
        };
        return Widget1;
    })();
    MyNamespace.Widget1 = Widget1;
})(MyNamespace || (MyNamespace = {}));

Using prototype in of itself is of course not a problem. However, since I changed my variables to be properties of ‘this’, a bug is born: ‘this’ in an event handler refers to the object that fired the event (in most browsers), not my object. Therefore the reference to ‘this._a’ refers to a most likely nonexistent property ‘_a’ on the DOM object that fired the event. We need to fix this by calling bind on the event handler function and getting a reference to a function that is bound to the correct ‘this’, like so

module MyNamespace
{
	export class Widget1
	{
		private inp : HTMLElement;
		private _a : number;
		private _b : number;
		
		constructor(inp:HTMLElement,a:number,b:number)
		{
			this._a = a;
			this._b = b;
			this.inp = inp;
		}

		public create() 
		{
                        // use bind to set this to the instance of Widget1 object not the object firing the event
			var click = this.click.bind(this);
			this.inp.addEventListener("keydown",click);

		}

		private click(e)
		{
			alert("clicked " + this._a);
		}

	}


}

THIS

 

Like I have mentioned in the previous posts, the code I am converting is several years old. One of the things it does is some browser detection on page load (a technique that is generally no longer in favor).  Changing the functionality or refactoring the code prior to TypeScript conversion however was not a goal.  During the conversion of this detector  object (which was not prototype or closure style) I started with something structured something like this:


var MyNamespace = MyNamespace || {};

MyNamespace.detector = {

    name: "4",
    init: function () {
        this.name = this.name + "test";
        this.other();
    }, 
    other: function () {
        this.name = "test3";
    },


    dostuff: function (x) {
        alert(this.name + ' ' + x);
    }
}


MyNamespace.detector.init();

MyNamespace.detector.dostuff('z');

And converted it to this TypeScript :


module MyNamespace
{
    export module detector
    {
        export var name : string = "4";

        export function init():void
        {
            this.name = this.name + "test";
            other();
        }

        function other():void
        {
            this.name = "test3";
        }

        export function dostuff(x:string):void
        {
            alert(this.name + ' ' + x);
        } 
    }

}

MyNamespace.detector.init();

MyNamespace.detector.dostuff('z');

The way the “other” function was handled led to issues.  I had essentially tried to make it private by not exporting it as it is not something external code would use directly. A quick glance at the code above might give one the impression that the alert would say ‘test3 z’ but in reality it shows ‘4test z’.  That is because the “this” in the function “other” is actually a different “this” than in “dostuff” or “init”.  The transpiled TypeScript code below makes it clearer why.  “this” in the function “other” is the function, while for “init” and “dostuff” it is the object “detector”.  The other catch with this situation is that TypeScript will happily let you assign to “this” in a standalone function, even if you set the “allow implicit any types” compiler directive off.  Secondly, the “export var name” is actually not required because of the way “this” is handled.  TypeScript will compile the file with no errors without that declaration.

My own advice from this “this” experience would be to wary of function exports from modules that use “this” and to check them carefully.  In my experience so far, using “this” in TypeScript classes has more protections.

var MyNamespace;
(function (MyNamespace) {
    (function (detector) {
        detector.name = "4";
        function init() {
            this.name = this.name + "test";
            other();
        }
        detector.init = init;

        function other() {
            this.name = "test3";
        }

        function dostuff(x) {
            alert(this.name + ' ' + x);
        }
        detector.dostuff = dostuff;
    })(MyNamespace.detector || (MyNamespace.detector = {}));
    var detector = MyNamespace.detector;
})(MyNamespace || (MyNamespace = {}));

MyNamespace.detector.init();

MyNamespace.detector.dostuff('z');

TYPESCRIPT PLUNGE

My plunge into TypeScript is to convert an existing proprietary ASP.NET Control Class Library, that uses C# on the server side, and Javascript on the client side from Javascript to TypeScript.   Although this library is in production use daily, there hasn’t been significant development on it  since it was first created back in the 2006-2007 timeframe.  As such, it is packed with older style Javascript.   There is also zero jQuery usage.  After the conversion, I expect another developer at my company may be able to modify it! (safely!).  The amount of code is not insignificant, there are about 20,500 total lines of Javascript spread across several files. Although I won’t post any of this closed source code here, I will put up some pseudo code that illustrates what I encounter.

The next step is to get TypeScript to work in a class library project, by default it does not.  This can be achieved be editing the project file in a text editor and changing the below from

  <Import Project="$(MSBuildBinPath)Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->

to

  <Import Project="$(MSBuildBinPath)Microsoft.CSharp.targets" />
  <Import Project="$(MSBuildExtensionsPath32)MicrosoftVisualStudiov$(VisualStudioVersion)TypeScriptMicrosoft.TypeScript.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->