TypeScript | 第五章:高級類型

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TypeScript系列學習筆記:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/40b485139fcbcb1ff516f5206","title":""},"content":[{"type":"text","text":"TypeScript | 第一章:環境搭建及基礎數據類型","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/b88d80d4393c65bb683e8199b","title":""},"content":[{"type":"text","text":"TypeScript | 第二章:類、接口和之間的關係","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/b88d80d4393c65bb683e8199b","title":null},"content":[{"type":"text","text":"TypeScript | 第三章:函數、泛型和枚舉","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/78797cf647a61945cbbac6530","title":""},"content":[{"type":"text","text":"TypeScript | 第四章:命名空間和模塊","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/1dfbd590a49ab0c003f69aef9","title":""},"content":[{"type":"text","text":"TypeScript | 第六章:理解聲明合併,以及編寫聲明文件","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/75eda12528ba620c9a8515afd","title":""},"content":[{"type":"text","text":"TypeScript | 第七章:配置文件說明","attrs":{}}]},{"type":"text","text":" ","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 交叉類型","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"交叉類型是將多個類型合併爲一個類型,用符號\"&\"表示。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 交叉類型實現的方式 extend(Person,Loggable) == Person & Loggable\nfunction extend(first: T, second: U): T & U {\n let result = {};\n for (let id in first) {\n (result)[id] = (first)[id];\n }\n for (let id in second) {\n if (!result.hasOwnProperty(id)) {\n (result)[id] = (second)[id];\n }\n }\n return result;\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 聯合類型","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"聯合類型表示一個值可以是幾種類型之一,用符號\"|\"分隔每個類型。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 聯合類型:padding若聲明爲any,編譯能通過,但運行時會報錯。\nfunction padLeft(value: string, padding: string | number) {\n if (typeof padding === \"number\") {\n return Array(padding + 1).join(\" \") + value;\n }\n if (typeof padding === \"string\") {\n return padding + value;\n }\n throw new Error(`Expected string or number, got '${padding}'.`);\n} ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 若值爲聯合類型,只能訪問此聯合類型的所有類型裏共有的成員\ninterface Bird{\n\tfly();\n layEggs();\n}\ninterface Fish{\n\tswim();\n layEggs();\n}\nfunction getPet():Bird|Fish{}\nlet pet = getPet();\npet.layEggs() // 正確,只能訪問共有的成員\npet.swim() // 錯誤","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. 自動類型推斷","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"1. typeof","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TypeScript可以將","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"typeof","attrs":{}}],"attrs":{}},{"type":"text","text":"識別爲一個類型保護,可以直接在代碼裏檢查類型了。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"let num:number|string = Math.random()>0.2?1:'1'\n// 類型必須是:\"number\", \"string\", \"boolean\"或 \"symbol\"\nif(typeof num ==='number'){ // 這裏稱爲typeof類型保護\n\tnum+=1\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2. instanceof","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"nstanceof","attrs":{}}],"marks":[{"type":"italic"}],"attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"類型保護","attrs":{}},{"type":"text","text":"是通過構造函數來細化類型的一種方式。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"let num:number|string = Math.random()>0.2?new Number(1):new String('1')\n\nif(num instanceof Number){ // 稱爲instanceof類型保護\n\tnum+=1\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"3. 瀏覽器API","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"document.onmousedown = e=>console.log(e) // 能自動推動出e爲MouseEvent","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4. 其他方式","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"let n = 1 ; //ts自動推斷出n爲number類型\n\nlet arr = [1] // 內部有數據,能推斷出正確類型\narr.push(2) // 正確\narr.push('3') // 錯誤,參數是string類型\n\nlet arr2 = [] // 未聲明類型,默認爲any[]\narr2.push(1)\narr2.push('2')","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4. null 和 undefined","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"默認情況,類型檢查器認爲","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"與","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"undefined","attrs":{}}],"attrs":{}},{"type":"text","text":"可以賦值給任何類型,它們是其它類型的一個有效值。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"--strictNullChecks","attrs":{}}],"attrs":{}},{"type":"text","text":"標記可以解決,聲明變量時不會自動包含","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"或 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"undefined","attrs":{}}],"attrs":{}},{"type":"text","text":"。可選參數會自動加上","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"| undefined","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"let s = \"a\";\ns = null; // 錯誤,null 不能賦值給string\nlet sn:string|null = 'b'\nsn = null; // 正常","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"5. 類型斷言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"告訴ts這是什麼類型,它都信。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"let obj = Math.random()>0.2?[]:1;\n\n// 方式一:\"<>\" 表示\n(obj).push(1)\n\n// 方式二:as表示\n(obj as number[])obj.push(1)\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"6. 類型別名","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類型別名會給一個類型起個新名字。 類型別名有時和接口很像,但是可以作用於原始值,聯合類型,元組以及其它任何你需要手寫的類型。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"型別名可以表示很多接口表示不了的類型, 比如字面量類型(常用來校驗取值範圍)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類型別名不能出現在聲明右側的任何地方。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"type Color = 'red'|'yellow'|'green'\ntype Num = 1|2|3\ntype Name = '張三'|'李四'\n\nlet a:Color = 'black' // 報錯,Color類型中沒有black\n\ninterface A{a:number}\ntype B = A | {b:number}\ntype C = A & {c:number}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"7. 索引類型","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ts中的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"keyof","attrs":{}}],"attrs":{}},{"type":"text","text":"和他類似, 可以用來獲取對象類型的鍵值。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// T[K], 索引訪問操作符\nfunction getProperty(o: T, name: K): T[K] {\n return o[name]; // o[name] is of type T[K]\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"type A = keyof {a:1,b:2} // 'a'|'b'\ntype B = keyof [1,2] // '1'|'2'|'push'...,不僅獲取內容,還獲取到Array原型上的方法","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"8. 映射類型","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"映射類型比較像修改類型的工具函數。","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"infer:待推斷/延遲推斷,根據實際情況推斷類型。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"1. Readonly","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義: 把每個屬性都變成只讀 \ntype Readonly={\n\treadonly (P in keyof T):T[P]; // 循環設置泛型T的屬性爲只讀\n}\n\ntype A = {a:number, b:string}\ntype AA = Readonly ","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"2. Partial","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:讓屬性都變成可選\ntype Partial = {\n\t[P in keyof T]?:T[P]\n}\n\ntype A = {a:number, b:string}\ntype AA = Partial // { a?: number; b?: string;}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"3. Required","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:讓屬性都變成必選\ntype Required = {\n\t[P in keyof T]-?:T[P]\n}\n\ntype A = {a?:number, b?:string}\ntype A = Required // { a: number; b: string;}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4. Pick","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:只保留自己選擇的屬性, K代表要保留的屬性鍵值\ntype Pick = {\n\t[P in K]:T[P]\n}\n\ntype A = Pick\ntype AA = Pick // {a:number,b:string}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"5. Omit ","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義: 實現排除已選的屬性\ntype Omit = Pick>;\n\ntype A = {a:number, b:string}\ntype AA = Omit // {b:string}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"6. Record","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:Construct a type with a set of properties K of type T\ntype Record = {\n [P in K]: T;\n};\n\ntype AA = Record // 等價{[x:string]:string}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"7. Exclude","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:過濾T中和U相同(或兼容)的類型\ntype Exclude = T extends U ? never : T;\n\ntype A = {a:number, b:string} \ntype AA = Exclude // number\n\n// 兼容\ntype A1 = Exclude // never , 因爲any兼容number, 所以number被過濾掉","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"8. Extract","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:提取T中和U相同(或兼容)的類型\ntype Extract = T extends U ? T : never;\n\ntype A = {a:number, b:string}\ntype AA = Extract // string","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"9. NonNullable","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:剔除T中的undefined和null\ntype NonNullable = T extends null | undefined ? never : T;\n\ntype A = NonNullable // number|string","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"9. ReturnType","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:獲取返回的返回類型\ntype ReturnTypeany> = T extends (...args:any)=>infer R?R:any\n\ntype A= ReturnTypenumber> // number","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"10. InstanceType","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 返回T的實例類型。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ts中類有2種類型, 靜態部分的類型和實例的類型, 所以","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"T","attrs":{}}],"attrs":{}},{"type":"text","text":"如果是構造函數類型, 那麼","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"InstanceType","attrs":{}}],"attrs":{}},{"type":"text","text":"可以返回他的實例類型:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:獲取構造函數類型的返回類型\ntype InstanceType any> = T extends new (...args: any) => infer R ? R : any;\n\ninterface A{\n a:HTMLElement;\n}\n\ninterface AConstructor{\n new():A;\n}\n\nfunction create (AClass:AConstructor):InstanceType{\n return new AClass();\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"11. Parameters","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:獲取函數參數類型,返回類型爲元祖, 元素順序與參數順序一樣.\ntype Parameters any> = T extends (...args: infer P) => any ? P : never;\n\ninterface A{\n (a:number, b:string):string[];\n}\ntype AA = Parameters // [number, string]","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"12. ConstructorParameters","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 定義:獲取構造函數的參數類型,T:構造函數類型\ntype ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never;\n\ninterface MyConstructor{\n new(a:number):number[];\n}\ntype AA = ConstructorParameters // [number]","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"9. extends","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"typescript"},"content":[{"type":"text","text":"// 條件類型:表示類型是不確定的,U可以表示T,則返回X,否則Y\nT extends U ? X : Y \n\ntype A = string extends 'a'?string:'a' // 'a'不能表示string類型,輸出 'a'\ntype B = 'a' extends string?string:'a' // string能表示'a',輸出 string\n\n// 類型過濾: 從T過濾掉可以賦值給U的\ntype Diff = T extends U?never: T;\ntype C = Diff // type C = 'a'|'c'\n// 過濾掉null,undefined\ntype NotNull = Diff\ntype D = NotNull // type D = string|number\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"10. 總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此完成了高級類型的學習,不完善的地方後續陸續補充。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章