# 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} /> ``` ---- ### 怎麼找? ![](https://i.imgur.com/sUwZzlY.png) ---- 運氣好的話<br>你會看到這個已匯出的型別定義 ![](https://i.imgur.com/7PRg2AB.png) ---- 匯入 ```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}]"}
    518 views