# TS 樂趣無窮
<h6 style='opacity:.7'>Sean Huang / 2021-08-10</h6>
---
## Interface 不加前綴 `I` 的理由
→ TS 本身就已達成標注型別的目的
----
### 額外的心智負擔
```typescript=
// 如果帕斯卡命名法對你來說合理...
interface IUser { name: string }
// 那何不也這麼做?
const SName = 'Sean' // "S" for String
const NAge = 18 // "N" for Number
const AFriends = [/*...*/] // "A" for Array
```
---
### `interface` 和 `type`
若前綴 `I` 僅是為了註明它是個 Interface...
----
🌰<br>分別以不同的方式宣告型別 `User`
```typescript=
// A.
interface IUser { name: string }
interface IUser { age: number }
```
```typescript=
// B.
type TUser = {
name: string,
age: number
}
```
```typescript=
// C.
type RUser =
Record<'name', string> &
Record<'age', number>
```
----
此例中,**IUser**、**TUser**、**RUser** 三者<strong style="color:#ffd019">完全等價</strong>
用 `interface` 宣告的那個並沒比較特別
這三個甚至都可被 `implements`<br><small>([https://pse.is/不騙你](https://pse.is/不騙你))</small>
----
> TypeScript 是🦆鴨子型別<br>(Duck Typing)
當看到一隻鳥走起來像🦆、<br>游泳起來像🦆、<br>叫起來也像🦆,<br>那麼這隻鳥就可以被稱為🦆
---
### 無需擔心型別和變數<br>會命名衝突
型別總是以<span style="color:#ffd019">大駝峰</span>命名
```typescript
type User = {
name: string,
age: number,
}
```
而變數總是以<span style="color:#ffd019">小駝峰</span>命名
```typescript
const user: User = {
name: 'Sean',
age: 23,
}
```
---
## 建議避免<span style="color:#ffd019">型別</span>與<span style="color:#ffd019"> MUI 組件</span>撞名
→ 容易混淆,一時難以分辨它是組件或是型別
----
🌰
```typescript=
import Dialog from '@material-ui/core/Dialog'
interface Dialog {
// ^^^^^^ 🥲 'Dialog' is already defined
'delete': DialogContent,
'deleteForbidden': DialogContent,
'deactivate': DialogContent,
}
```
### ↓
```typescript=
interface DialogContents { /*...*/ } // 👍
```
---
## 建議<span style="color:#ffd019">型別</span>和<span style="color:#ffd019">變數</span>命名高度相關
----
🌰<br>MUI 的 Pagination 組件(節錄)
```typescript=
// @material-ui/lab/Pagination/Pagination.d.ts
interface PaginationProps {
color?: 'primary' | 'secondary' | 'standard'
}
function Pagination(
props: PaginationProps
): JSX.Element;
```
----
| 變數名 | 型別名 |
| - | - |
| `props` | `PaginationProps` 或 `Props` |
| `state` | `DialogState` 或 `State` |
> 💡 可根據上下文<br>自行決定是否省略修飾語
---
## 請直接向套件拿型別
----
🌰(節錄)
```typescript=
const handleClose = (
event?: React.SyntheticEvent, // 🤔
reason?: string // 😑
) => {
/* ... */
}
```
```jsx=
<Snackbar onClose={handleClose} />
```
----
### 怎麼找?

----
運氣好的話<br>你會看到這個已匯出的型別定義

----
匯入
```typescript=
import Snackbar, { SnackbarProps }
from '@material-ui/core/Snackbar'
```
指定 handler 的型別
```typescript=
const handleClose: SnackbarProps['onClose'] = (
event, // React.SyntheticEvent<any, Event>
reason, // SnackbarCloseReason
) => {
/* ... */
}
```
🎉 得到符合組件要求的參數型別
```jsx=
<Snackbar onClose={handleClose} />
```
---
## 解決日益增長的 `src/constants/type.ts`
→ 抽出型別成獨立檔案並置於 `src/types`
例如 `Controller.ts`、`Model.ts`
> K7 建議:目錄結構請參考 container 和 component
---
## 關於混搭 BS 和 MUI 樣式
→ 只用 BS 的網格相關 class 如 `.row` 、 `.col` 、 `.container` 等;
其餘用 MUI 的組件如 `<Box />`
---
## 參考資料
- https://github.com/SunshowerC/blog/issues/7
{"metaMigratedAt":"2023-06-16T06:15:52.549Z","metaMigratedFrom":"Content","title":"TS 樂趣無窮","breaks":true,"contributors":"[{\"id\":\"3861e094-21dd-48a0-9ba5-3cb3e62ef32d\",\"add\":5718,\"del\":2524}]"}