Skip to content

typescript

For a quick course : visit

Typescript is javascript with strong typing.

All typescript is transpilable with :

install
sudo npm install -g typescript
tsc -v

Tsc is the typescript compiler, and it converts .ts files into plain .js files.

typing

Typescript can be plain javascript, in which case the compiler does very little:

example
1
2
3
4
5
6
7
8
function greeter(person) {
    return "Hello, " + person;
}
var user = "Jane User"

let text = greeter(user)

console.log(text)

Becomes :

becomes this javascript
1
2
3
4
5
6
function greeter(person) {
    return "Hello, " + person;
}
var user = "Kees";
var text = greeter(user);
console.log(text);

Mainly, var keywords are replaced, lines end with ';' and some whitespace is removed.

As a reminder, let is the same as not using a keyword at all, and it has block scope, while var has function scope. As a quick test you can see the difference with :

var
1
2
3
console.log(x)
var x = 5
console.log(x)

This prints :

var output
undefined
5

But removing the var (or changing it to let) will give an error :

let output
ReferenceError: x is not defined

Type checking can be added to .ts code by placing the type behind a variable. These are called type annotations.

type checking
1
2
3
4
5
6
7
function greeter(person: string) {
    return "Hello, " + person;
}

let user = "Kees";
let text = greeter(user);
console.log(text);

The above code is no longer javascript, so nodejs won't run it. But we can turn it back into javascript with :

make javascript
tsc js.ts # maakt js.js 
node js.js # Hello, Kees";

Placing anything else than a string in the user variable gives a typescript error. :

type errors
t.ts:6:20 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

Note that even though there were errors, the typescript still compiled a javascript program !

interfaces

Interfaces and classes are implemented in typescript but on top of the normal prototypical inheritance.

interface
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person : Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = { firstName: "Kees", lastName: "Klop" }
let text = greeter(user);
console.log (text);

After transpilation, it will revert to the javascript:

transpiled
1
2
3
4
5
6
function greeter(person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}   
var user = { firstName: "Kees", lastName: "Klop" };
var text = greeter(user);
console.log(text);

Though now there is being checked if person has the required members. Changing firstName: 11 will work just fine in the .js file, but leads to an error in the .ts file. Just as it will lead to an error if you use any other membername than firstName of lastName, it does not follow the Person interface !

classes

Classes can also be used and mixed with interfaces.

classes
class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");

console.log(greeter(user));

There is no explicit link but you use a Student class objects in a function with a Person parameter and tsc complains when they don't have matching parameters. For instance changing the firstName to fName in the Student class leads to this error :

output
p.ts:19:22 - error TS2345: Argument of type 'Student' is not assignable to parameter of type 'Person'.
Property 'firstName' is missing in type 'Student' but required in type 'Person'.

And it is on line 19, the call to greeter() . If you remove that call, nothing is violated and there is no error.

not assignable problem

This particular problem when compiling a typescript file :

ERROR in src/app/jsonrpc.service.ts(37,13): error TS2345: Argument of type 'import("/home/kees/projects/klopt/planner/src/app/location").Location' is not assignable to parameter of type 'Location'.

This happens when you reuse a name already used in the supporting code. In my case a created a LocationBuilder class that was used to create instances of Location. Location was already a type somewhere deeper down, i do not know where. But Changing Location in MyLocation made this error disappear.

So investigate namespaces !! For now i am going to prepend stuff with the Kk prefix.

faker not working

The generation of fake orders and trucks fails with this message in the javascript console:

ERROR TypeError: Cannot read property 'company' of undefined

This is a result of altering the setting module: "commonjs" in tsconfig.js.get rid of some warning I did that to get rid of some warnings about commonjs/amd.

The module parameter steers the typescript compilers module handling. From the TypeScript site :

error
1
2
3
Specify module code generation: "None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015" or "ESNext".
► Only "AMD" and "System" can be used in conjunction with --outFile.
► "ES6" and "ES2015" values may be used when targeting "ES5" or lower.

To get rid of the warnings, just do NOT upgrade your node_modules until they have a way to suppress the warnings.

Do not upgrade the frontend in-place, do a tryout in a separate branch and only switch if that works without problems.

If npm audit reports severe problems, do an assessment.

For instance, npm audit reported a high vulnerability in http-proxy but that was only used by lite-server, which is a development module. In development we do not greatly care about vulnerabilities.

In this case.. I first removed the lite-server module to see if it is used at all. It was not.

TypeError stream expected

core.js:6241 ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

The code looks like this :

code
fakeOrders(num: number) {
    this.deleteAllOrders();

    const arr = [];
    for (let i = 0; i < num; i++) {
        let { x,y } = Utils.nlcoords();
        const o = new Order(0,
        faker.company.companyName(),
        faker.random.number(),
        new LocationBuilder().
            setXY(x,y).build(),0,"Unplanned");
        arr.push(this.ordersvc.insertOrder(o));
    }
    console.log(arr);
    forkJoin(arr).subscribe(results => {
        console.log(results);
        this.loadOrders();
    });
}

We fill an array of...