Friday, 11 February 2022

TypeScript

Types

/** a is type of any */
let a

/** a is type of number */
let a :number;

/** if initalize when define, will figure out type. Here is number too*/
let a=1

/** possible types */
let a :number
let b :boolean
let c :string
let d :any

/** type aliases */
type Age = number
let age :Age = 55

type Person = {name:string, age:Age}
let driver:Person = {name:"leo", age:age}

/** below is array type */
let e : number[] = [1,2,3]

/** enum type. Red will assign to be 0 .... */
enum Color {Red, Green, Purple, Yellow}
/** use enum */
let myColor = Color.Green
/** will show 1 */
console.log(myColor)

/** tuple tyep. It is similiar to array. However, it can consist different types*/
let person:[string, number] = ['john', 30]
console.log(person.length)

person.push("male")
console.log(person)

/**the following will generate error because boolean is not allowed in person tuple.*/
person.push(true)

Literal types

literal type's value can ONLY be itself. It mostly is used by combining literals into unions

let x: "hello" = "hello";
let i:3=3

Interface as type

interface Point {
    x: number;
    y: number;
}

let p:Point = {x:1, y:2}
console.log(p)

//create array of points
const points: Point[] = [
    {x:1, y:2},
    {x:2, y:8}
]

Type Assertion

Set the type of value and ask compiler not to infer it

/** although code is defined as type any, we can set it to be number*/
let code: any = 123; 
let employeeCode = <number> code; 

/** another way. in jsx, should use this way */
let code: any = 123; 
let employeeCode = code as number;

Class

class Point {
    x: number;
    y: number;
    constructor(x:number, y:number) {
        this.x = x
        this.y = y
    }
    draw() {
        console.log(this.x)
        console.log(this.y)
    }
}

let p = new Point(1,6 )
p.draw()

We can reduce some lines of code for the above example. The below will behave the same as above. Actually, they will generate the same js code.

class Point {
    constructor(public x:number, public y:number) {
        
    }
    draw() {
        console.log(this.x)
        console.log(this.y)
    }
}

let p = new Point(1,6)
p.draw()

Also can make constructor parameter optional

 constructor(x:number, y?:number) {
        this.x = x
        this.y = y
    }

Accessors in class

class Point {
    constructor(private x:number, private y:number) {
        
    }

    get X() {
        return this.x
    }

    set X(val) {
        this.x = val
    }

    draw() {
        console.log(this.x)
        console.log(this.y)
    }
}

/** will output 1, 12, 6*/
let p = new Point(1,6)

/** access x by X */
console.log(p.X)

/** modify x by setter X */
p.X = 12
p.draw()

When complie, get error

tsc main.ts

 error TS1056: Accessors are only available when targeting ECMAScript 5 and higher
 
 //to solve the error:
 tsc -t es5 main.ts
 
 test.ts:2:21 - error TS2583: Cannot find name 'Map'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2015' or later.
//to solve
tsc -t es2015 test.ts

Use tsconfig.json

Create a tsconfig.json

tsc --init

To use it. Only type tsc. Will try to use setting in tsconfig.json and convert ts files into js files.

#watch mode
tsc --watch

Prevent from generating js file if there is error in ts file, set the below

"noEmitOnError": true

To prevent from compiling libraies files(node_modules), set

"skipLibCheck": true

Generics

This is simliar to what Java has done. The type can be dynamic in defining the function and can pass along the type variable. When call the function, specify the type.

function check<Type>(arg:Type):Type {
    return arg
}

let ans = check<string>("good")
console.log("ans:", ans)

let ans2 = check<number>(99)
console.log(ans2)

When we say an array of some type, we can do: Array<T>. Create a new Array of T: new Array<T>()

function cpArray<T>(items : T[] ) : T[] {
    return new Array<T>().concat(items);
}

let myNumArr = cpArray<string>(["a", "b"]);

HashMap

HashMap Methods

//Leetcode 2206
function divideArray(nums: number[]): boolean {
    let myMap = new Map<number, number>();
    
    for (let n of nums) {
        if (myMap.has(n)) {
            myMap.set(n, 1+myMap.get(n))
        } else {
            myMap.set(n, 1)
        }
    }
    
    for (let k of myMap.keys()) {
        if (myMap.get(k)%2 !=0) {
            return false
        }
    }
    return true

};

Install TypeScript locally

npm init -y
install typescript --save-dev

To use it:

npx tsc [cmd]
npx tsc -v

Use stage 2 decorator

  • tsc version > 5
  • disable experimental decorator config flag!( if enabled, will go back to stag 1 syntax)

Check optional parameter

//output: person age is undefined
interface Person {
  name: string;
  age?: number;
}

let p: Person = {
  name: "leo",
};

if (p.age === undefined) {
  console.log("person age is undefinde");
} else {
  console.log("person age is defined");
}

Solve exports Error

After compile ts file and try to run it in browser, got the following error.

app.js:2 Uncaught ReferenceError: exports is not defined

Here is original ts files

// myModule.ts
export class MyClass {
    public greet() {
        return "Hello from MyClass!";
    }
}

export function myFunction() {
    return "Hello from myFunction!";
}

//app.ts
import { MyClass, myFunction } from './myModule';

const instance = new MyClass();
console.log(instance.greet()); // Output: "Hello from MyClass!"
console.log(myFunction()); // Output: "Hello from myFunction!"

The following is app.js got

//app.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const myModule_1 = require("./myModule");
const instance = new myModule_1.MyClass();
console.log(instance.greet()); // Output: "Hello from MyClass!"
console.log((0, myModule_1.myFunction)()); // Output: "Hello from myFunction!"
To solve the problem
  • change index.html
    -  <script src="dist/app.js" defer></script>
    +  <script type="module" src="dist/app.js" ></script>
  • change app.ts
    -import { MyClass, myFunction } from './myModule';
    +import { MyClass, myFunction } from './myModule.js';
  • change tsconfig.json (in "compilerOptions" section)
    -    "module": "commonjs",                                
    +    "module": "es2015",  

app.js got after applying the above changes

//app.js
import { MyClass, myFunction } from './myModule.js';
const instance = new MyClass();
console.log(instance.greet()); // Output: "Hello from MyClass!"
console.log(myFunction()); // Output: "Hello from myFunction!"

No comments:

Post a Comment