各種 Type 機制
- primitive type  TS 中型別有兩種:primitive type、object type其中 primitive type (原始型別) 有:boolean、number、string、null、undefined 和 ES6 的 Symbol- 宣告方式 - let a: boolean = false;
 let b: number = 98;
 let c: string = "test";
 let d: string = `${c}123`; // 嵌入變數
 let e: undefined = undefined;
 let f: null = null;
 console.log(a);
 console.log(b);
 console.log(c);
 console.log(d);
 console.log(e);
 console.log(f);
- 不回傳用 - void- function test(num: number): void {
 console.log(num);
 }
 test(87);
 
- Union- 宣告方式用 - |來分隔型別- // 可以是 string or number 型別
 let a: string | number
 a = 'test'
 console.log(a)
 a = 87
 console.log(a)
- 用在 function,只能使用 - 共同的方法、屬性- toString()是 number、string 共同的方法,所以可以使用;如果改成- length會報錯- function getString(something: number | string): string {
 return something.toString()
 }
 console.log(getString(98))
 console.log(getString('test'))
- union type 的變數被 assign 時,會根據型別推論的規則推斷出當下型別 - let something: string | number
 // 目前是 string
 something = 'test'
 console.log(something.length)
 // 目前是 number
 something = 98
 console.log(something.length) // 會報錯
 
- Pick (從一個型別中取出子集當成一個型別)- 可以增加閱讀性 - type Info = {
 name: string;
 age: number;
 account: string;
 password: string;
 phoneNumber: string;
 };
 // 從 Info 裡面取出 password,phoneNumber 成為一個新的 type
 type Secret = Pick<Info, "password" | "phoneNumber">;
 const secret: Secret = {
 password: "password",
 phoneNumber: "0987654321",
 };
 
- Record- 將兩個 type 組成一個分別是 key,value 的新 type - type CatName = 'A' | 'B' | 'C'
 type CatInfo = {
 age: number
 breed: string
 }
 // Record<CatName, CatInfo> 是一個物件
 // key 是 CatName,value 是 CatInfo
 const cats: Record<CatName, CatInfo> = {
 A: { age: 5, breed: 'AAA' },
 B: { age: 10, breed: 'BBB' },
 C: { age: 15, breed: 'CCC' }
 }
 
- Partial / Required- Partial: 屬性都變成 - option
- Required: 屬性都變成 - 必須- type Student = {
 name?: string
 age: number
 }
 type PartialStudent = Partial<Student>
 type RequiredStudent = Required<Student>
 const student: Student = { age: 20 }
 const partialStudent: PartialStudent = {}
 const requiredStudent: RequiredStudent = { name: 'Sam', age: 27 }
 
- Intersection type &- 對 object type 會取 - 聯集- type Identity = {
 id: string
 name: string
 }
 type Contact = {
 phone: string
 email: string
 }
 type Employee = Identity & Contact
 const employee: Employee = {
 id: 'A001',
 name: 'Tom',
 phone: '0123456789',
 email: 'abc@gmail.com'
 }
- 對 union type 會取 - 交集- type A = string | number
 type B = string | boolean
 // 會是交集
 type C = A & B // string
 
- Any & Unknown  相同地方:- 都可以接受任意型別 - 不同地方: 
- any 可以 assign 給任何型別 
- unknown 只能 assign 給 any or unknown 
- any 可以任意操作屬性 or 方法 
- unknown 要執行 - 型別斷言或- 型別檢查才能操作屬性 or 方法且通過編譯- Any
- any 可以被 assign 任意型別 - // any 可以被 assign 任意型別
 let a: any = "test";
 console.log(a);
 a = 87;
 console.log(a);
 a = true;
 console.log(a);
- 宣告時不指定型別,就會是 any - // 等同於 let something: any;
 let something;
 something = true;
 console.log(something);
 something = 98;
 console.log(something);
- any 的問題 - let a: any = 19;
 let str: string = a;
 // 編譯時期沒事,但執行時期會錯
 console.log(str.toLowerCase());- Unknown
- 只能 assign 給 - unknownor- any- let a: unknown = 19;
 // assign 給 unknown & any
 let b: unknown = a;
 let c: any = a;
 // 會報錯!!
 let str: string = a;
- 沒有推斷是什麼型別之前,禁止操作屬性與方法 - let a: unknown = "123";
 if (typeof a === "string") {
 console.log(a.toUpperCase()); // 推斷後可以用方法
 }
 
- Never  用途:- 無窮迴圈 - function infiniteLoop(num: number): never {
 while (true) {
 console.log(num)
 }
 }
- throw exception - function generateError(message: string): never {
 throw new Error(message)
 }
 
- Omit (忽略特定屬性)type Todo = {
 title: string
 description: string
 completed: boolean
 createdAt: number
 }
 type TodoPreview = Omit<Todo, 'description' | 'createdAt'>
 const todo: TodoPreview = {
 title: 'Finish recap 2021',
 completed: false
 }