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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章