Avisi Blog

Typescript for Java(script) developers

Geschreven door Avisi | 16 August 2018

Sander organized a Techday about Typescript at the 26th of July. This blog is based on that Techday. Do you want to join our next Techday? Sign up on our Meetup page.

 

TypeScript for Java(script) developers

Modern web applications contain more and more JavaScript code. But nevertheless many Java developers are still reluctant to write large JavaScript applications. Looking at myself, it took me ages to really take the plunge. But at some point, it became inevitable to take the plunge. Typescript really helped me in taking the next step into JavaScript development.

 

This blog post is written to help Java and JavaScript developers to start developing in TypeScript. I am aware that this is a rather long blog post! If you want to quickly jump to the practical part, scroll down to the Getting started section.

 

JavaScript vs. ECMAScript

Short after its introduction in 1996, Netscape made the effort to turn JavaScript into an industry standard. This standard is called ECMAScript (ES). JavaScript is a dialect of ECMAScript. The last version of JavaScript (1.8.5) was released in 2011, shortly after the ECMAScript 5 release. ECMAScript 5 is still the best supported version of JS/TS in all modern browsers. Although ECMAScript is releasing new versions of the language every year since 2015, browser integration is still an issue.

 

Then TypeScript came along. With version 1.0 released in 2013, TypeScript is quickly adopting new language features from the latest ECMAScript releases and adding its own on top of it. TypeScript then compiles towards the version of ECMAScript of your choice.

 

Differences between TypeScript & JavaScript


TypeScript is developed by Microsoft in 2012 as a superset of JavaScript, which means that JavaScript code will work in TypeScript without modification. All language concepts available in JavaScript can be used in TypeScript as well. But you would be unwise to do so because TypeScript can make your life so much easier!

 

TypeScript introduces the concepts of classes, namespaces and modules, finally added the desperately required structure to JavaScript development. Instead of declaring everything in the global context, you can now create a namespace of your own to prevent naming conflicts. A simple TypeScript example looks like this:

 

export default namespace Example {
    export class Hello {
        constructor(private message: string = "Hello World!") {}
        sayHello(): string {
            return this.message;
        }
    }
}

 

The code above declares a class Hello with the method sayHello() in the namespace "Example". Both the namespace Example and the class Hello are exported to be used outside this module.

 

Variable declaration

Variable declaration in TypeScript is the most dramatic change over JavaScript. First of all, variables should always be declared with the keyword let instead of var, to prevent redeclaration of variables and also ensures scope safety.

 

There is a lot to say on types, that can be read here as well. A special type is the type never which get assigned to functions with an unreachable endpoint (e.g. endless loop or always throwing an error) and to variables for which the type can not be determined (e.g. var stringArray = [] ).

 

JavaScript is still untyped. With TypeScript, you can rely on the TypeScript compiler to validate the code. But after compilation, the resulting JavaScript will still be untyped.

 

TypeScript for Java developers

As a Java developer it took me some time to get started with JavaScript development. When you are used to object-oriented development and a strictly checked language, it is rather difficult to work in a language that completely lacks these features. TypeScript brings a lot of what Java developers experience as commodity back into JavaScript.

 

The This keyword

As a Java developer you expect "This" to always point at the class you are in. In JavaScript this works differently. The "This" keyword in JavaScript references the context the code is called from, which can be confusing sometimes. TypeScript solved most of the issues with "This". When working in a class within TypeScript, "This" points to the context of that class, as expected.

 

But when you pass a method to a function for callback, the context from which this method is called is different. Then, "This" does not reference the context of the class anymore. To make sure "This" points to the context in which is was declared (the class), you have to use the fat arrow (=>) syntax for the function declaration. When using the fat arrow, "This" will be assigned at the moment of declaration instead of when the function is called. The syntax for the fat arrow looks like this:

 

() =>  = 
(x: number) => number = function(n1: number): number { return n1*n1; }

In fact, every function in TypeScript has the structure as you can see above. All other ways of declaring a function are short-hand notations for the above. Let's rewrite the Hello example above towards this syntax.

 

export default namespace Example {
    export class Hello {
        constructor(private message: string = "Hello World!") {}
        () => string = sayHello(): string {
            return this.message;
        }
    }
}

 

TypeScript for JavaScript developers

Starting with TypeScript as a JavaScript developer is easy. Since JavaScript is also valid TypeScript, no code changes are required at start. JavaScript developers will need to learn the new concepts and unlearn some behavior in the way they were writing code. The TypeScript compiler has some options to gradually move JavaScript developers into the more strict environment of TypeScript. All is very nice described in a tutorial for migrating from JavaScript.

 

As a JavaScript developer, the most important thing is to unlearn your typical JavaScript constructions. When transitioned to pure TypeScript you are also ready for the future and able to rely on the TypeScript compiler to gradually build code for the newer browsers with having to completely rewrite your code-base again. The compiler can compile to the following outputs: "ES3" (default), "ES5", "ES6"/"ES2015", "ES2016", "ES2017" or "ESNext".

 

The advantage of using TypeScript over JavaScript is that you can use a language of its own that can compile to different versions of the underlying language to support different sets of browsers. At the moment most modern browsers support ES5 whereas ES6 support is still limited and ES2018 (ES7) is low.

 

Getting started

TypeScript is available through NPM. To install the TypeScript compiler, install Node.Js and type npm install -g typescript (Leave the -g option if you want the module in your local project only).

 

Getting started for Java developers

  • Create the folder ```src/main/ts``` and copy all your JavaScript sources in it.
  • Install the Grunt typescript plugin and create a Gruntfile.js in the root of your project:

module.exports = function(grunt) {
    grunt.initConfig({
        // ----- Environment
        // read in some metadata from project descriptor
        project: grunt.file.readJSON('package.json'),
        // define some directories to be used during build
        dir: {
            // location where TypeScript source files are located
            "source_ts": "src/main/ts",
            // location where all build files shall be placed
            "target": "target",
            // location to place (compiled) javascript files
            "target_js": "target/classes/js",
        },
        // ----- TypeScript compilation
        //  See https://npmjs.org/package/grunt-typescript
        typescript: {
            // Compiles the code into a single file. Also generates a typescript declaration file
            compile: {
                src: ['<%= dir.source_ts %>/**/*.ts'],
                dest: '<%= dir.target_js %>',
                options: {
                    base_path: '<%= dir.source_ts %>',
                    target: 'ES6',
                    declaration: false,
                    comments: false
                }
            }
        },
    });
    // ----- Setup tasks
    grunt.loadNpmTasks('grunt-typescript');
    grunt.registerTask('default', ['typescript:compile']);
};
  • Create a packages.json to configure npm modules:
{
  "name": "HelloWorld",
  "version": "1.0.0-SNAPSHOT",
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-cli": "1.2.0",
    "grunt-typescript": "^0.8.0",
    "ts-node": "^5.0.1",
    "tslint": "^5.10.0",
    "typescript": "^2.7.2"
  },
  "dependencies": {}
}
  • Modify your pom.xml to contain the following plugin config:

<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<!-- Use the latest released version:
https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ -->
<version>1.6</version>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<!-- See https://nodejs.org/en/download/ for latest node and npm (lts) versions -->
<nodeVersion>v8.9.4</nodeVersion>
<npmVersion>5.6.0</npmVersion>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<!-- Optional configuration which provides for running any npm command -->
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>grunt build</id>
<goals>
<goal>grunt</goal>
</goals>
<configuration>
<arguments>--no-color</arguments>
</configuration>
</execution>
</executions>
</plugin>
  • run mvn compile to compile your code

 

Getting started for JavaScript developers

  • Create a tsconfig.json in the root of your project with the following options:

 

{
    "compilerOptions": {
        "outDir": "./target/js",
        "allowJs": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
        "allowUnreachableCode": true,
        "allowUnusedLabels": true,
        "target": "es5"
    },
    "include": [
        "./src/**/*"
    ]
}
  • Set the correct outDir and includes and compile your code.

 

Next steps

  • Configure your IDE integration: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support
  • Gradually make your compiler more strict with the following options: --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks, --strictFunctionTypes and --strictPropertyInitialization.
  • Set allowUnreachableCode and allowUnusedLabels back to false.

 

Conclusion

Thanks for bearing with me to the end! For me, TypeScript really helped to develop better JavaScript code with fewer errors. Furthermore, it is very nice to have one single language and be able to generate code for different versions of JavaScript. If you want to play around or test certain concepts of TypeScript, then check this out: https://www.typescriptlang.org/play/ 

 

Some references for further reading:

  1. http://www.typescriptlang.org/
  2. https://www.npmjs.com/package/grunt-typescript
  3. https://compat-table.github.io/compat-table/es6/
  4. https://en.wikipedia.org/wiki/ECMAScript
  5. https://en.wikipedia.org/wiki/JavaScript#Version_history
  6. https://atom.io/packages/atom-typescript
  7. https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support
  8. https://www.typescriptlang.org/play/
  9. https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html