Category Archives: Javascript

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


YUI COMPRESSOR SINGLE FILE GENERATOR FOR VS2013

In the past I used a Javascript and CSS minifier in Visual Studio that I built on top of the original YUI compressor.  I implemented it via a Custom Tool / Single File Generator.  I figured this might be helpful with minifying the output of TypeScript.  I wanted to eliminate the Java dependency however, so  I built the generator on top of YUI Compressor.NET.  Unfortunately, this doesn’t seem to work for my situation.  When TypeScript generates new Javascript output it doesn’t seem to trigger the SFG to do its thing.   In any case I put the source on Github for anyone who is interested.

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.

DEBUGGING BOOKS 2

So I slacked off a little on my reading Pro AngularJS and also detoured a bit into reading up on Bootstrap since I am relatively inexperienced with it and the book more or less assumes you know it (or will at least ignore it 🙂 ).

I started reading through Chapter 7 and encountered some issues with the following code:

angular.module(&quot;sportsStore&quot;)
    .constant(&quot;dataUrl&quot;, &quot;http://localhost:5500/products&quot;)
    .controller(&quot;sportsStoreCtrl&quot;, function ($scope, $http, dataUrl) {

        $scope.data = {};

        $http.get(dataUrl)
            .success(function (data) {
                $scope.data.products = data;
            })
            .error(function (error) {
                $scope.data.error = error;
            });
    });

In the section “Handling Ajax Errors” the author states “The object passed to the error function defines status and message properties.”.  Actually this is not the case, the error function should have the signature

.error(function (data, status, headers, config) {

Also, the first parameter is not an error object, it is the response data. For example in the case of a 404 error it would be the returned HTML 404 page.

The following code should make the example work


            .error(function (data, status, headers, config) {
                $scope.data.error = {};
                $scope.data.error.data = data;
                $scope.data.error.status = status;
            });

Secondly to test the error handling and achieve a 404 error, the author states in a tip to change the URL to something like ‘http://localhost:5500/doesNotExist’. This will most likely not work , as the site is running under nodejs on port 5000, and Deployd is hosting under port 5500, the browser will see this as a CORS request and most likely not return any error information, similar to the angular issue described in the link below. If you want to get a 404 error change the URL to a non-existent relative URL something like ‘/doesNotExist’, this will be relative to the site URL and be a non-CORS request.

CORS Error Response Status = 0

https://github.com/angular/angular.js/issues/2798

PACE OF CHANGE AND DEBUGGING BOOKS

I started reading the book “Pro AngularJS” written by Adam Freeman.  This book was published on April 1st 2014.  I’ve read Freeman’s books before (Pro ASP.NET MVC X) and found them to be informative.

I followed the instructions in Chapter 1 for “How Do You Set Up Your Development Environment”, which basically entails using nodejs as a simple web server for hosting your angular and bootstrap files.

So I install node, install the connect module,  copy in the simple server.js code shown here:

var connect = require('connect');

connect.createServer(
    connect.static("../angularjs")

).listen(5000);

I  run node server.js and I get  “TypeError: Object function createServer(), has no method ‘static’”

TypeError

Well, after a bit of investigation, it appears that the connect module has been reorganized, the author most likely used version 2.x, but looking at the connect module release history, version 3.0 was released on 5/29/2014. In fact the release candidate for 3.0 first appeared to be published in March, so that explains why the book doesn’t use the newer version.

To fix so it works with v3.0 of the connect module, also install the module ‘serve-static’ using the command

npm install serve-static

The replacement code that works is as follows:

var connect = require('connect')
var serveStatic = require('serve-static')

var app = connect();

app.use(serveStatic('../angularjs'));

app.listen(5000);

Alternatively, you can install an older version of connect. Looking over the history indicates that 2.13.0 would most likely be the best choice.

npm install connect@2.13.0

So far I’ve learned a bit about node, installing older versions of packages and the changes to the connect module without even reading much of the book 🙂

Hopefully the rest of the examples in the book run with less research!

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