# 🏅 Day 7 - 介面(interfaces) ### 介面是啥? 在 TypeScript 裡頭,介面(Interface)是用來定義物件的型別。 在不使用 Interfaces 以前,我們都必須用型別註釋來定義物件參數,內容會寫得很冗長。但 Interfaces 可以有效解決這個問題。 ### 基本範例 ```tsx= interface Student { studentId: number; name: string; } // 正確 let bob: Student = { studentId: 101, name: 'Bob' }; // 錯誤,只可指定已知的屬性,且 'Student' 中沒有 'gender'。 let Tom: Student = { studentId: 101, name: 'Tom', gender:'male' // 會報錯 }; ``` 這裡定義了一個 **`Student`** 介面,然後建立了一個符合這個介面的物件 **`bob`**。 TypeScript 要求物件必須跟介面的定義完全一致,物件多出或少了介面中的屬性都不行。 ### 可選屬性 如果有些屬性是選擇性的,可以用問號(?)來設計: ```tsx interface Student { studentId: number; name: string; grade?: number; } // 正確 let alice: Student = { studentId: 102, name: 'Alice', grade: 90 }; // 正確 let lily: Student = { studentId: 103, name: 'Lily' }; ``` ### 任意屬性 如果想讓介面可以接受任何其他屬性,可以這樣寫: ```tsx interface Student { studentId: number; name: string; grade?: number; [propName: string]: any; } let john: Student = { studentId: 104, name: 'John', department: 'History' }; ``` 用 **`[propName: string]`** 表示除了已定義的屬性外,介面還可以接受任何其他的額外屬性。 ### 唯讀屬性 如果某些屬性在建立後就不想讓它改變,可以用 **`readonly`** : ```tsx interface Student { readonly studentId: number; name: string; } let mike: Student = { studentId: 105, name: 'Mike' }; // mike.studentId = 106; // 這行會報錯,因為 studentId 是唯讀的 ``` 像是上面 **`studentId`** 被設定,就不能再更改。 ## 常用情境 1. **定義物件的形狀(Shape)**:當你需要預先定義一個物件應該包含哪些屬性和方法時,介面是非常合適的選擇。特別是在大型項目或團隊協作中。 2. **強化函式參數的型別檢查**:當你需要函式接受帶有特定屬性的物件時,可以使用介面來定義這些屬性,來提高程式碼的可讀性和可維護性。 3. **定義複雜的資料結構**:當處理複雜的資料結構,例如從 API 取得的大型 JSON 物件時,介面可以幫助你管理和理解這些資料結構的形狀,不用每次都需要通靈。 ## 情境一:定義物件的形狀(Shape) ### **範例情境:使用者資訊管理系統** 在這個系統需要處理使用者資訊,像是姓名、年齡和電子郵件地址。為了確保在整個應用程式中一致處理這些資訊,我們可以用介面來定義一個「使用者」的形狀。 ### 定義「使用者」介面 ```tsx // 重點:定義使用者的形狀 interface User { name: string; age: number; email: string; } function displayUser(user: User) { console.log(`Name: ${user.name}, Age: ${user.age}, Email: ${user.email}`); } let user1: User = { name: "陳大明", age: 30, email: "damingchen@example.com" }; displayUser(user1); ``` 透過這樣的方式確保在整個應用程式中,所有處理使用者資訊的地方都會遵循同一個結構和型別,藉此提高程式碼的一致性和可靠性。 ## 情境二:強化函式參數的型別檢查 ### **範例情境:商品庫存管理系統** 一個商品庫存管理系統。我們需要處理各種商品的庫存狀況,包括商品名稱、數量和價格。為了確保函式能夠接收正確格式的商品資訊,我們可以用介面來強化函式參數的型別檢查。 ### 定義「商品」介面 ```tsx= interface Product { id: string, name: string, quantity: number, price: number } // 重點:參數在型別註釋,使用 Product 介面 function updateInventory(product: Product, additionalQuantity: number) { product.quantity += additionalQuantity; console.log(`更新 ${product.name}: ${product.quantity} 品項到庫存`); } let newProduct: Product = { id: "A105", name: "筆記型電腦", quantity: 20, price: 45000 }; // 新增特定產品庫存量 updateInventory(newProduct, 5); ``` 透過使用介面來強化函式參數的型別檢查,確保函式只接受符合特定結構的物件,這樣一來可以減少錯誤,又能提高代碼的可靠性 :D ## 情境三:定義複雜的資料結構 ### **範例情境:線上課程平台的課程資訊管理** 假設六角學院正在開發一個線上課程平台,需要處理各種課程的詳細資訊,包括課程名稱、講師資訊、課程內容和學生評價等。由於這些資料結構相對複雜,就適合用介面來定義這些結構。 ### 定義相關介面 ```tsx= // 講師介面 interface Instructor { name: string; expertise: string[]; } // 課程介面,重要,有發現到這裡用到了 Instructor 介面嗎? interface Course { title: string; description: string; instructor: Instructor; rating: number; reviews: string[]; } // 顯示課程資訊 function displayCourseInfo(course: Course) { console.log(`課程名稱: ${course.title}`); console.log(`課程描述: ${course.description}`); console.log(`講者名稱: ${course.instructor.name}`); console.log(`課程評價: ${course.rating}/5`); } let programmingCourse: Course = { title: "進階 TypeScript 程式設計", description: "深入瞭解 TypeScript 的高階特性。", instructor: { name: "王小明", expertise: ["TypeScript", "JavaScript", "軟體工程"] }, rating: 4.5, reviews: ["很實用的課程!", "深入淺出,易於理解。"] }; displayCourseInfo(programmingCourse); ``` 像是這範例中,**`Instructor`** 介面定義了講師的姓名 (**`name`**) 和其專長領域 (**`expertise`**)。當 **`Course`** 介面中引用 **`Instructor`** 介面時,就表明每個課程都會有一位講師,並且這位講師的資訊會遵循 **`Instructor`** 介面的結構。 ### 這樣的好處是在 1. **模組化和重用性**:通過將 **`Instructor`** 作為一個獨立的介面,我們可以在很多地方重用這個介面。這種模組化方法讓程式碼更加清晰,並減少重複性。 2. **清晰的結構定義**:將講師的資訊封裝在自己的介面中,可以讓 **`Course`** 介面的結構更加清晰。 3. **易於維護和擴充**:如果未來講師的資訊需要添加新的屬性或修改,我們只需更改 **`Instructor`** 介面。這種設計讓整個系統更容易維護和擴充。 <span style="color:blue">學到這裡,相信你開始可以理解,其實學 TypeScript 其中一個主要原因,就是為了讓資料結構上的可讀性、可維護性變得更高。 </span> <span style="color:blue">所以正在學 TypeScript 的你/妳,在挽起袖子準備寫程式前,先把後端工程師的 API 資料結構拿去分析,並思考哪些內容可以拆出適當的 TypeScript 型別,有助於你開發上變得更順利 🙌</span> ## 單選題 1. **在 TypeScript 中,interface 主要用於:** A. 定義函數的返回值 B. 儲存資料 C. 定義物件的形狀 D. 計算數值 2. **在 TypeScript 的 interface 中,可選屬性是如何表示的?** A. 使用前綴符號 **`?`** B. 使用前綴符號 **`#`** C. 使用後綴符號 **`!`** D. 使用後綴符號 **`^`** 3. **TypeScript 的 interface 可以用於哪種情況?** A. 定義一個變數的數值 B. 管理複雜的資料結構 C. 進行數學運算 D. 設定程式的背景顏色 ## 開發任務:醫院病患和預約管理系統 ### 目標 **前工程師寫到一半烙跑了**,所以你才有機會得到這份工作~ヽ(́◕◞౪◟◕‵)ノ **你的任務是接手他的糙 Code,來設計醫院病患和預約管理系統。** ### 任務描述 1. **定義介面** - **`Patient`** 介面:應包含病患的姓名(**`name`**)、年齡(**`age`**)、性別(**`gender`**)和病歷號碼(**`medicalRecordNumber`**)。 - **`Appointment`** 介面:應包含預約的日期(**`date`**)、時間(**`time`**)、醫生姓名(**`doctorName`**)和病患病歷號碼(**`patientMedicalRecordNumber`**),用來關聯病患的病歷號碼。 2. **實作資料結構** - 建立一個 **`patients`** 陣列,用於儲存 **`Patient`** 物件。 - 建立一個 **`appointments`** 陣列,用於儲存 **`Appointment`** 物件。 3. **開發功能** - 實作函式 **`addPatient`** 來添加新病患到 **`patients`** 陣列。 - 實作函式 **`scheduleAppointment`** 來為存在的病患安排新的預約,並加入到 **`appointments`** 陣列。 - 實作函式 **`cancelAppointment`** 來取消現有的預約。 - 實作函式 **`listAppointments`** 來列出特定病患的所有預約。 ## 工程師寫到一半繞跑的程式碼 ```tsx // 定義 Patient 病患介面 interface Patient { name: string; age: number; gender: string; medicalRecordNumber: string; } // 定義 Appointment 預約介面 interface Appointment { date: string; time: string; doctorName: string; patientMedicalRecordNumber: string; } // 病患資料陣列 let patients: Patient[] = []; // 預約資料陣列 let appointments: Appointment[] = []; // 實作函式 addPatient function addPatient(patient: Patient): void { patients.push(patient); } // 實作函式 scheduleAppointment function scheduleAppointment(appointment: Appointment): void { // 確保病患存在 const patientExists = patients.some( (patient) => patient.medicalRecordNumber === appointment.patientMedicalRecordNumber ); if (!patientExists) { throw new Error("病患不存在,要確欸"); } // TODO: 增加一筆預約到預約列表 } // TODO: 函式 cancelAppointment // TODO: 實作函式 listAppointments // 增加病患 addPatient({ name: "John Doe", age: 30, gender: "Male", medicalRecordNumber: "12345" }); // 安排預約 scheduleAppointment({ date: "2024-01-15", time: "10:00", doctorName: "Dr. Smith", patientMedicalRecordNumber: "12345" }); ``` ## 回報流程 將答案寫在 CodePen,並貼至底下回報就算完成了喔! 解答位置請參考下圖(需打開程式碼的部分觀看) ![](https://i.imgur.com/vftL5i0.png) <!-- 解答: 單選題目:C、A、B --> 回報區 --- | Discord | CodePen / 答案 | |:-------------:|:----------------------------------------------------------------:| |洧杰|[Codepen](https://codepen.io/hexschool/pen/poYgYqW?editors=1010)| |神奇海螺|[Codepen](https://codepen.io/hexschool/pen/poYgYqW?editors=1010)| |ZS|[Codepen](https://codepen.io/irishuang/pen/MWxJXQV)| |HsienLu|[Codepen](https://codepen.io/Hsienlu/pen/vYPgrmB)| |YC|[HackMD](https://hackmd.io/SKoJd3EsTlitnjzCx4Rarg?view)| |BonnieChan|[Codepen](https://codepen.io/Bonnie-chan-the-bold/pen/oNVByVN?editors=1012)| |苡安|[Codepen](https://codepen.io/yi-an-yang/pen/MWxJXor)| |LinaChen|[Codepen](https://codepen.io/LinaChen/pen/bGZgmRB)| |Jack|[Codepen](https://codepen.io/lj787448952/pen/YzgNRXq)| | hannahpun|[Codepen](https://codepen.io/hannahpun/pen/ZEPLmjg)| |hannahTW|[Codepen](https://codepen.io/hangineer/pen/poYRKqL?editors=0011)| |Henry_Wu|[Codepen](https://codepen.io/hekman1122/pen/JjzExeq?editors=1011)| |展誠|[Codepen](https://codepen.io/hedgehogkucc/pen/LYaxoPJ?editors=1012)| |Bryan Chu|[CodePen](https://codepen.io/bryanchu10/pen/JjzEQXj)| |薏慈|[CodePen](https://codepen.io/its_wang/pen/poYRXoK?editors=1010)| |Mia Tsai|[CodePen](https://codepen.io/Mianzi/pen/yLwgmYL)| |jasperlu005|[Codepen](https://codepen.io/uzzakuyr-the-reactor/pen/ZEPLgrp?editors=1011)| |rikku1756|[Codepen](https://codepen.io/rikkubook/pen/wvOgVEV?editors=1111)| |Mi|[CodePen](https://codepen.io/Mi-Jou-Hsieh/pen/dyrNxvJ?editors=1010)| |deedee1215|[CodePen](https://codepen.io/diddy032/pen/jOJygQW)| |Alyce|[CodePen](https://codepen.io/alycehwy/pen/ZEPezvr)| |Kai|[CodePen](https://codepen.io/kaiyuncheng-the-styleful/pen/GReWJQJ?editors=0012)| |yunhung|[CodePen](https://codepen.io/ahung888/pen/JjzWGgv)| |77_0411|[CodePen](https://codepen.io/chung-chi/pen/bGZgrEJ?editors=1010)| |hiYifang|[HackMD](https://hackmd.io/@gPeowpvtQX2Om6AmD-s3xw/SkhePfMKa)| |Amberhh| [codepen](https://codepen.io/Amberhh/pen/poYebjK?editors=1011)| |連小艾|[Codepen](https://codepen.io/bolaslien/pen/zYbZBqX?editors=1011)| |m_m|[CodePen](https://codepen.io/minnn7716/pen/MWxpbYp)| |Yang|[Codepen](https://codepen.io/Yang-J/pen/WNmRPqX)| |clairechang|[Notion](https://claire-chang.notion.site/Day-7-interfaces-62d98123e2994bbab3a058e7f1749fb3)| |JC|[Codepen](https://codepen.io/jcsamoyed/pen/vYPxKoe?editors=0012) |Zuo|[Codepen](https://codepen.io/linchinhsuan/pen/RwdpZgy?editors=1010) |Otis|[CodePen](https://codepen.io/humming74/pen/eYXvEQB?editors=1010)| |Lisa|[CodePen](https://codepen.io/lisaha/pen/PoLpzYW?editors=1012)| |wendy_.li|[HACKMD](https://hackmd.io/PcmFgqZwRd-4Ep3-LgK5_Q) |Starr|[CodePen](https://codepen.io/StarrZhong/pen/zYbZdbz) |NiuNiu|[CodePen](https://codepen.io/Dawson-the-bold/pen/OJqpNRP?editors=0011) |翰毅|[CodePen](https://codepen.io/yzuigtdw-the-animator/pen/WNmpdoW?editors=1111)| | fanshu0303 | [CodePen](https://codepen.io/JuiHsuanLee0303/pen/OJqpeKv) | | Teddy | [CodePen](https://codepen.io/TaideLi/pen/ExMmyWM) | |wei|[CodePen](https://codepen.io/jweeei/pen/NWJjNWK?editors=1011)| |erwin阿瀚|[CodePen](https://codepen.io/yohey03518/pen/LYaywNN)| |精靈|[CodePen](https://codepen.io/justafairy/pen/NWJgjYP)| |shan13|[CodePen](https://codepen.io/yishan13-tsai/pen/KKEqvLO)| |皓皓|[HackMD](https://hackmd.io/@cutecat8110/Sy5JVpPt6)| |小米|[HackMD](https://codepen.io/joanne-wei/pen/qBvjxWm?editors=0010)| |ethan1331|[CodePen](https://codepen.io/EthanTsai/pen/MWxoZmx)| |Snorlax|[HackMD](https://hackmd.io/@snorlaxpock/BkjOf2jK6)| |Yoshi|[CodePen](https://codepen.io/yoshiyyc/pen/YzgYPLK)| |Nick Lin|[CodePen](https://codepen.io/NickLinP/pen/ZEPvYKv?editors=1111)| |Rochel|[Codepen](https://codepen.io/rochelwang1205/pen/xxBWRJN?editors=1012)| |leave3310|[Codepen](https://codepen.io/leave3310-the-looper/pen/LYaerZY?editors=0011)| |aki|[codepen](https://codepen.io/aki168/pen/abMKOyG)| |Tori|[Hackmd](https://hackmd.io/OAdkiOH-S_WkD-LF6IONVA?view)| puffy|[Codepen](https://codepen.io/TernMayDay/pen/bGZZLXY?editors=0010) | 我是泇吟 | [Codepen](https://codepen.io/kljuqbxs/pen/zYVQZpZ) |