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