# Note - 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 的優點?
型別檢查
課程大綱

* 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

```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
使用時機:非常確信他的值

```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)
```