--- tags: blog --- # 以「陰陽」理解 TypeScript 的 Type 和 Value 🌗 ## *Value*(值) *value* 就是在執行時期,能夠在表達式中引用的變數。 例如 `let x = 5` 會建立一個叫做 `x` 的 *value*,而且可以透過 `console.log(x)` 把值印出來。 :::success 🌕 我喜歡用陰陽的**陽**來形容 *value* ::: ES6(JavaScript 本來就有的): 1. 以 `let`、`const` 和 `var` 宣告的 value 1. `function` 1. `class` 1. 引用 value 的 `import` TypeScript 特有的: 1. `enum` 1. 包含 value 的 `namespace` 或 `module` ## *Type*(型別) :::success 🌑 我會用**陰**來形容 *type*。 我們並沒辦法拿型別執行來做運算,因為它們僅僅是用來標註型別用的,且經編譯後就會丟棄這些型別的訊息。 ::: 在 TypeScript 能以下列方法建立 *type*: 1. type 例如 `type sn = number | string` 1. interface 例如 `interface I { x: number[] }` 1. class 💙 例如 `class C { }` 1. enum 💙 例如 `enum E { A, B, C }` 1. 引用 type 的 `import` ## 💙 能同時建立 *Value* 和 *Type* 的特例 1. `class` 1. `enum` 稱它們為特例的原因是,由這兩個關鍵字宣告出來的東西,同時是 *value* 也是 *type*。且不像一般的 *type*,它們經編譯後依然會被留下來。 ### `class` 範例 ```typescript= // 宣告叫做 Student 的 class class Student { name: string age: number constructor (name: string, age: number) { /* ... */ } } // 可以將 `Student` 當 value 用: // 例如透過 new 來建立一個實例 const sean = new Student('黃省喬', 24) // 也可以將 Student 當 type 用: // 例如用來宣告列表型別 `Students` type Students = Student[] // 或是當作參數的型別 const 點名 = (student: Student) => { console.log(`🙋 ${student.name}`) } 點名(sean) ``` ### `enum` 範例 ```typescript= // 宣告叫做 Status 的 enum enum Status { idle = 0, loading = 1, success = 2, failure = 3, } const isSuccess = (status: Status) => { return status === Status.success } ``` 可至 [TypeScript Playground](https://www.typescriptlang.org/play?#code/KYOwrgtgBAygLgQzmAzlA3gKClAlgEwBtgoBeKABgBpspCB7BfXEAczKgEYacUwBjfsBRpyAJh5QAZglyEwAJxLkAzDQC+mTP3ogUcPChgChIjgAp9SVAC5YiZCgCUZAHwZaS5ApBQrjslJyeGsUADo+QWEUTHUgA) 查看這段程式碼的 enum 是如何被編譯的 ## 如何打破「陰陽」的隔閡? 也就是,該如何反推某個**值**來得到它的**型別**? → **`typeof`** :::info 只能從某個 🌕 value 得到它的 🌑 type; 反過來想從 🌑 type 得到 🌕 value 則是辦不到的。(上述特例除外) ::: ```typescript= // 宣告一個物件🌕 const sushi = { name: '🍣', price: 40, isRaw: true, } // 使用 `typeof` 關鍵字取得物件的型別🌑 type Food = typeof sushi // { name: string, price: number, isRaw: boolean } // 取得 `Food` 的所有鍵的型別🌑 type KeyOfFood = keyof Food // "name" | "price" | "isRaw" // 取得 `Food` 的所有值的型別🌑 type ValueOfFood = Food[KeyOfFood] // string | number | boolean ``` :::warning ⚠️ 此處的 `typeof` 是 TypeScript 的關鍵字,注意別和 JavaScript 的運算子 `typeof` 混淆了! ::: ## 參考資料 https://www.typescriptlang.org/docs/handbook/declaration-files/deep-dive.html