---
# System prepended metadata

title: Ｎote - understanding TypeScript - 2022 Edition

---

# Ｎote - understanding TypeScript - 2022 Edition

## 學習資源包

1. official website -> documentation & playground
2. project or ex: angular, nest.js baed on node js for the server side
3. google for typescript example

---


> 什麼是 typescript ? 

TS is js superset ie a language building up on JS 

TS 增加新的功能與優勢在原本的 js 上，但有一個大大的缺點，TS 無法在 JS 環境上執行 (瀏覽器無法執行)，但這不表示我們無法使用它，TS 是一個程式語言也是一個工具，可以編譯 TS to JS

> TS 如何增加新的 feature 在 regular JS 上？

TypeScript compiler compiles these new features to JavaScript workarounds.

> TS 的優點？
型別檢查

課程大綱

![](https://i.imgur.com/Yb5XRYr.jpg)


* typeCasting let ts know which type it will be


ts 會 compile 成 js 這種寫法原生的 js 是不能接受的

```ts
const button = document.querySelector("button");
const input1 = document.getElementById("num1")! as HTMLInputElement; // this will always find an element
const input2 = document.getElementById("num2")! as HTMLInputElement;

function add(num1: number, num2: number) {
  if (typeof num1 === "number" && typeof num2 === "number") {
    return num1 + num2;
  } else {
    return +num1 + +num2;
  }
}

button.addEventListener("click", function () {
  console.log(add(+input1.value, +input2.value));
});

```

install node.js 就可以使用 npm command

npm init 會產出 package.json

--save-dev 只有開發環境會用到的

lite server 是簡易版的開發環境用的 server which always servers index.html file next to package.json

# 核心語法與 feature

TS 有超多型別，甚至可以做出屬於自己獨一無二的型別

> js 使用這些型別與 ts 使用這些型別的意義與差異為何？

JS uses dynamic types(resolves at runtime), typescript uses static types(set during development)

* JS 是動態地型別，所以在 runtime 我們會用 typeof 去檢查型別，目的是確保後續地代碼如果有依賴到相對應的型別
* TS 是靜態型別，他們不會在 runtime 改變型別．(ts 最終會編譯成 js，理論上是可做到 js 動態型別地效果．)，可以在 development 時進行型別檢查，另外與 js 相比 type 更豐富

## Core Type

![](https://i.imgur.com/K6goQyV.png)

```js
const add = (num1, num2) => {
    return num1 + num2 // 102.4
}

const number1 = '10'
const number2 = 2.4

const result = add(number1, number2)
console.log(result)
```

by adding a colon here after the value to which we want to assign a type.


> TS 只在編譯的時候幫忙我們，他並沒有改變 JS 的運行，（瀏覽器是不能運行 TS 的，It can only help us during development before we compile our TypeScript code to JavaScript.


我們可以透過 JS 提供的 typeof 去檢查型別，但缺點是型別錯誤是在 runtime 才會報錯的

**The core primitive types in TypeScript are all lowercase!** ex: It is string and number (etc.), NOT String, Number etc.



Note: 
1. app.js & app.ts 同時打開，IDE 會報錯因為重複的 function 執行，
2. tsc fileName.js -> it compiles the typescript file and spits out a JavaScript file.


---

# [Basic Type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)
## primitive type
### Numnber & String & Boolean
1. ts js 都是一樣的，所有的 number 的預設值都是 floats

```ts
const add = (num1:number, num2:number, showResult: boolean, phrase: string) => {
    if (showResult) {
        console.log(`${phrase} ${num1 + num2}`)
    } else {
        return num1 + num2
    }

}

const number1 = 10
const number2 = 2.4
const printResult = true
const resultPhrase = "result is: "

const result = add(number1, number2, printResult, resultPhrase)
```
## type inference
ts understand which type you have in a certain variable or a constant.

可以在變數後面加 : 型別，但如果你有賦值給他，這其實是多餘且不好的寫法，因為 ts 可以去推斷你所使用的型別，除非初始化時沒有賦值給他


```ts
// bad
let number1: number  = 10

// good
let number1: number
number1 = 5;

// ts inferred that we store a string 
// get error -> we store a number
let resultPhrase = "result is: "
resultPhrase =111
```

### object type

```ts
// generic object type
const person: object = {
    name: "Angela",
    age: 26
}
// setting specific object type
const person: {
    name: string;
    age: number;
} = {
    name: "Angela",
    age: 26
}

// nested obj
{
  id: string;
  price: number;
  tags: string[];
  details: {
    title: string;
    description: string;
  }
}

const product = {
  id: 'abc1',
  price: 12.99,
  tags: ['great-offer', 'hot-and-new'],
  details: {
    title: 'Red Carpet',
    description: 'A great carpet - almost brand-new!'
  }
}
```

### array type

```ts

const person: {
    name: string;
    age: number;
    hobbies: string[]
} = {
    name: "Angela",
    age: 26,
    hobbies: ['Cooking', 'Painting']
}

for (const hobby of person.hobbies) {
    console.log(hobby.toUpperCase())
}

```
----
## Type script add not for vanilla JS
### Tuple
fixed length and fixed types array

push 是 tuple 的例外

```ts
const person: {
    name: string;
    age: number;
    hobbies: string[],
    role: [number, string] // tuple
} = {
    name: "Angela",
    age: 26,
    hobbies: ['Cooking', 'Painting'],
    role: [2, 'teacher']
}

person.role.push('admin') // 檢查會過
person.role = [1, 'doctor', 'Female'] // 會被 ts 擋下
```
### Enum

having a couples of specific identifiers, global constants, you want to assign a human readable label

通常 enum 都是大寫，但這不是必要，只是慣例; enum default start at zero



```ts

// 缺點是要定義這些常數並維護他們
const ADMIN = 0;
const READ_ONLY = 1;
const AUTHOR = 2

const person: {
    name: string;
    age: number;
    hobbies: string[],
    role: number,
} = {
    name: "Angela",
    age: 26,
    hobbies: ['Cooking', 'Painting'],
    role: ADMIN
}

// 使用 enum 好處是閱讀性提升，另外可指定 mapped value 
enum Role { ADMIN = 10, READ_ONLY = 2, AUTHOR = 100 }

const person: {
    name: string;
    age: number;
    hobbies: string[],
    role: number
} = {
    name: "Angela",
    age: 26,
    hobbies: ['Cooking', 'Painting'],
    role: Role.ADMIN
}
```

### Any

沒事不要用到它

### Union Type
depend on your logic, some case need run time check 

```ts
const combine = (inputOne: number | string, inputTwo: number | string) => {
    let result: number | string;
    if (typeof inputOne === 'number' && typeof inputTwo === 'number') {
        result =  inputOne + inputTwo
    } else {
        result = inputOne.toString() + inputTwo.toString()
    }
    return result
}

const combineAge = combine(20, 30);
const combineName = combine('Amy', 'Nick')

```

### Literal Type
使用時機：非常確信他的值

![](https://i.imgur.com/EB5LtNj.png)



```ts
const combine = (inputOne: number | string, inputTwo: number | string, resultConversion: string) => {
    let result: number | string;
    if (typeof inputOne === 'number' && typeof inputTwo === 'number' || resultConversion === 'as-number') {
        result =  +inputOne + +inputTwo
    } else {
        result = inputOne.toString() + inputTwo.toString()
    }
    return result
}

// 缺點：不能傳錯值，可以用 enum 改善，
// 但因為這邊只有兩個值，所以 literal type 會更合適
const combineAges = combine(20, 30, 'as-number');
console.log(combineAges)

const combineStringAges = combine('20', '33', 'as-number')
console.log(combineStringAges)

const combineNames = combine('Amy', 'Nick', 'as-text')
console.log(combineNames)
```

```ts
const combine = (
  inputOne: number | string,
  inputTwo: number | string,
  resultConversion: "as-number" | "as-text"
) => {
  // 略
};

```

### Type Aliases / Custom Types

with ts keyword `type` ＋ 別名，將你想要封裝的型別寫在 aliases 裡面 

```ts
// make reusable type aliases here!!!
type CombinAble = number | string
type ConversionDescriptor = "as-number" | "as-text"

const combine = (
  inputOne: CombinAble,
  inputTwo: CombinAble,
  resultConversion: ConversionDescriptor
) => {
  let result: CombinAble;
  if (
    (typeof inputOne === "number" && typeof inputTwo === "number") ||
    resultConversion === "as-number"
  ) {
    result = +inputOne + +inputTwo;
  } else {
    result = inputOne.toString() + inputTwo.toString();
  }
  return result;
};

```

alias 也可以是 object

```ts
type User = { name: string; age: number };
const u1: User = { name: 'Max', age: 30 };

type User = { name: string; age: number };
 
function greet(user: User) {
  console.log('Hi, I am ' + user.name);
}
 
function isOlder(user: User, checkAge: number) {
  return checkAge > user.age;
}
```

### Function

#### Return 
return type is inferred by ts; 若有特地目的要指定 function 回傳型別可以這麼做

```ts
const add =  (n1: number, n2: number): number =>  {
    return n1 + n2
};
```

void -> function return nothing but not undefined

如果你使用 undefined, ts 會預期 return undefined

```ts
const add =  (n1: number, n2: number): undefined =>  {
    return 
};

const printResult = (num: number): void => {
 console.log(`Result is ${num}`)
}
```

#### Type

Function Types are types describe a function regarding the parameters and return value

```ts
const add =  (n1: number, n2: number): number =>  {
    return n1 + n2
};

const printResult = (num: number): void => {
 console.log(`Result is ${num}`)
}
// 缺點，沒有指定他是哪一個 function
let combinValues: Function;
combinValues = add
combinValues  = printResult // 出錯了
console.log(combinValues(1, 15))

// 改善
let combinValues: (a: number, b: number) => number;
combinValues = add
```
### cb

這邊的寫法 `=> void`，不是指強迫你 cb 不能回傳東西，而是說任何回傳的東西都不會被使用到

callback functions can return something, even if the argument on which they're passed does NOT expect a returned value.

```ts
// cb: ignore any result you return 
const addAndHandle = (n1: number, n2: number, cb: (num: number) => void) => {
  const result = n1 + n2;
  cb(result);
}

addAndHandle(12, 30, (result) => {
    console.log(result)
    return 123 // 這也是為何沒有報錯
})
```

### Unknow Type

不該常用，但比 any 好，因為至少你還得做一些型別檢查，才能將 unknown 的值 assign 給 fixed type

```ts
let userInput: unknown
let userName: string

userInput = 5;
userInput = 'ABC'

if (typeof userInput === 'string') {
    userName = userInput
}
```

### Never Type
error is thrown -> it cancels our script，當然可以用 try catch 讓 script 繼續

never return anything

```ts
// 使用時機：throw error / infinite loop
const generateErr = (message: string, code: number): never => {
    throw({errorMessage: message, errorCode: code})
    // while(true) {}
}

generateErr('Invalid XXX', 500)
```
