TypeScript 高階型別
阿新 • • 發佈:2021-08-09
1 /** 2 * @name sfxATypes 3 * @author shenyc 4 * @date 2021-08-09 5 * @copyright Copy right (c) shenyc ([email protected]). 6 * All rights reserved. 7 * @remark The Advance type in typeScript 8 * 9 ******************************************************************************/ 10 11 // 避免把 TypeScript 寫成 AnyScript: 12 // 當應用越來越複雜,我們很容易把一些變數設定為 any 型別,TypeScript 寫著寫著也就成了 AnyScript。 13 /** 14 * 1、避免把 TypeScript 寫成 AnyScript: 15 * 當應用越來越複雜,我們很容易把一些變數設定為 any 型別,TypeScript 寫著寫著也就成了 AnyScript。 16 */ 17 18 /** 19 * 基礎型別 20 */ 21 let b: Boolean = true; 22 let s: String = ''23 let n: Number = 0; 24 let e: null = null; 25 let u: undefined = undefined; 26 let o: Object = {}; 27 28 /** 29 * 陣列 30 */ 31 let as: String[] = []; 32 let ag: Array<Number> = [1, 2, 3]; 33 let ai: Int16Array = new Int16Array(); 34 35 /** 36 * 介面 37 */ 38 interface IPerson {39 age: number; 40 name: string; 41 42 } 43 44 /** 45 * 類 46 */ 47 class Person implements IPerson { 48 age: number; 49 name: string; 50 } 51 class Famer extends Person { } 52 53 /** 54 * 泛型 55 */ 56 function Foo<T>() { 57 // console.log(typeof T); 58 } 59 60 /** 61 * 高階型別 - 交叉型別(&) 62 */ 63 interface A { id: number; }; 64 interface B { name: string; }; 65 let tab: A & B = { 66 id: 10, 67 name: "123" 68 }; 69 70 /** 71 * 高階型別 - 聯合型別(|) 72 */ 73 let tu: Boolean | Number | String; 74 tu = true; 75 tu = 1; 76 tu = "123"; 77 78 /** 79 * 高階型別 - 類型別名(type) 80 */ 81 type StringLike = String | String[]; 82 let talias: StringLike = undefined; 83 talias = '0'; 84 talias = ['', '']; 85 86 /** 87 * 型別索引(keyof) 88 */ 89 interface Button { 90 type: string; 91 text: string; 92 } 93 94 type ButtonKeys = keyof Button; 95 96 97 /** 98 * 型別約束(extends) 99 */ 100 function print<T extends String>(arg: T): void { 101 console.log(arg); 102 } 103 104 // extends 經常與 keyof 一起使用, 105 // 例如我們有一個方法專門用來獲取物件的值,但是這個物件並不確定, 106 // 我們就可以使用 extends 和 keyof 進行約束。 107 function getValue<T, K extends keyof T>(obj: T, key: K) { 108 return obj[key] 109 } 110 111 const obj = { flag: 1 } 112 const a = getValue(obj, 'flag') 113 114 /** 115 * 型別對映(in) 116 * 117 * in 關鍵詞的作用主要是做型別的對映,遍歷已有介面的 key 或者是遍歷聯合型別。 118 * 下面使用內建的泛型介面 Readonly 來舉例。 119 */ 120 121 interface Obj { 122 a: string 123 b: string 124 } 125 126 type ReadOnlyObj = Readonly<Obj> 127 128 /** 129 * 條件型別(U ? X : Y) 130 */ 131 type CommonKeys = Extract<keyof Person, keyof Famer> 132 133 134 /** 135 * 工具泛型 136 * 137 * TypesScript 中內建了很多工具泛型,前面介紹過 Readonly、Extract 這兩種, 138 * 內建的泛型在 TypeScript 內建的 lib.es5.d.ts 中都有定義,所以不需要任何依賴都是可以直接使用的。 139 * 下面看看一些經常使用的工具泛型吧。 140 */ 141 142 /** 143 * 工具泛型 - Partial 144 * 用於將一個介面的所有屬性設定為可選狀態 145 */ 146 interface IMan { 147 age: number; 148 name: string; 149 } 150 151 let one: IMan = { 152 // 必須設定所有屬性 153 age: 0, 154 name: "one" 155 }; 156 157 let two: Partial<IMan> = { 158 // 所有屬性都是可選屬性 159 }; 160 161 162 /** 163 * 工具泛型 - Required 164 * * Required 的作用剛好與 Partial 相反,就是將介面中所有可選的屬性改為必須的 165 */ 166 interface C { 167 x?: number; 168 s?: string; 169 } 170 171 let cobj1: C = {}; 172 let cobj2: Required<C> = { x: 0, s: '', }; 173 174 /** 175 * Record 176 * Record 接受兩個型別變數,Record 生成的型別具有型別 K 中存在的屬性,值為型別 T。 177 * 這裡有一個比較疑惑的點就是給型別 K 加一個型別約束,extends keyof any,我們可以先看看 keyof any 是個什麼東西。 178 */ 179 interface Food { 180 id: string 181 name: string 182 price: string 183 image: string 184 } 185 const goodsMap: Record<string, Food> = {}; 186 const goodsList: Food[] = []; 187 188 goodsList.forEach(food => { 189 goodsMap[food.name] = food; 190 }) 191 192 193 /** 194 * Pick 195 * Pick 主要用於提取介面的某幾個屬性。 196 */ 197 interface Todo { 198 title: string 199 completed: boolean 200 description: string 201 } 202 type TodoPreview = Pick<Todo, "title" | "completed">; 203 204 const todo: TodoPreview = { 205 title: 'Clean room', 206 completed: false 207 } 208 209 /** 210 * Exclude 211 * Exclude 的作用與之前介紹過的 Extract 剛好相反, 如果 T 中的型別在 U 不存在,則返回,否則拋棄。 212 */ 213 interface Teacher { 214 name: string 215 age: number 216 email: string 217 salary: number 218 } 219 220 interface Student { 221 name: string 222 age: number 223 email: string 224 grade: number 225 } 226 227 type ExcludeKeys = Exclude<keyof Teacher, keyof Student> 228 // => salary, 取出的是 Teacher 在 Student 中不存在的 salary。 229 230 /** 231 * Omit 232 * Omit 的作用剛好和 Pick 相反 233 * 先通過 Exclude<keyof T, K> 先取出型別 T 中存在,但是 K 不存在的屬性, 234 * 然後再由這些屬性構造一個新的型別。 235 * 還是通過前面的 Todo 案例來說,TodoPreview 型別只需要排除介面的 description 屬性即可,寫法上比之前 Pick 精簡了一些。 236 */ 237 interface Something { 238 id: number; 239 name: string; 240 description: string; 241 } 242 type SomethingOmit = Omit<Something, "description"> 243 // => SomethingOmit { id: number; name: string; } 244 245 246 /** 247 * 最後是變數的型別 248 */ 249 let x: string = '123' 250 let xtype = typeof x;