[{"data":1,"prerenderedAt":526},["ShallowReactive",2],{"content:\u002F2023\u002Ftypescript\u002Fts-9":3,"surround:\u002F2023\u002Ftypescript\u002Fts-9":515},{"id":4,"title":5,"body":6,"categories":489,"date":492,"description":24,"draft":493,"extension":494,"image":495,"meta":496,"navigation":498,"path":499,"permalink":495,"published":495,"readingTime":500,"recommend":495,"references":495,"seo":505,"sitemap":506,"stem":511,"tags":512,"type":513,"updated":495,"__hash__":514},"content\u002Fposts\u002F2023\u002Ftypescript\u002Fts-9.md","泛型编程（上）",{"type":7,"value":8,"toc":474},"minimark",[9,13,17,28,31,39,45,51,58,64,69,75,78,81,84,89,92,98,101,107,110,116,119,125,129,134,152,158,163,169,175,182,192,210,213,216,222,235,241,247,261,269,275,294,301,307,313,320,329,335,339,348,354,357,363,368,374,378,384,404,407,412,421,448,452,458],[10,11,12],"h2",{"id":12},"泛型就像函数",[14,15,16],"p",{},"函数",[18,19,25],"pre",{"className":20,"code":22,"language":23,"meta":24},[21],"language-js","const f = (a, b) => a + b\nconst result = f(1, 2) \u002F\u002F 3\n","js","",[26,27,22],"code",{"__ignoreMap":24},[14,29,30],{},"泛型",[18,32,37],{"className":33,"code":35,"language":36,"meta":24},[34],"language-ts","type F\u003CA, B> = A | B\ntype Result = F\u003Cstring, number> \u002F\u002F string | number\n","ts",[26,38,35],{"__ignoreMap":24},[14,40,41],{},[42,43],"img",{"alt":12,"src":44},"\u002Fimages\u002Ftypescript\u002Fts-9\u002Fts_9_01.png",[46,47,48],"blockquote",{},[14,49,50],{},"函数的本质是什么",[14,52,53,54],{},"函数的本质是",[55,56,57],"strong",{},"推后执行的、部分待定的代码",[18,59,62],{"className":60,"code":61,"language":23,"meta":24},[21],"\u002F\u002F 立即执行\nconsole.log(1)\n\n\u002F\u002F 推后一步执行\nconst f1 = () => console.log(1)\nf1()\n\n\u002F\u002F 推后两步执行\nconst f2 = () => console.log(1)\nconsole.log(2)\nf2()\n\n\u002F\u002F 部分待定的\nconst f3 = (fn, n) => fn(n) \u002F\u002F 参数待定\nf3(console.log, 3)\n",[26,63,61],{"__ignoreMap":24},[46,65,66],{},[14,67,68],{},"泛型的本质是什么",[14,70,71,72],{},"泛型的本质是",[55,73,74],{},"推后执行的、部分待定的类型",[14,76,77],{},"没有泛型的类型系统，就如同没有函数的编程语言",[10,79,80],{"id":80},"什么时候需要泛型",[14,82,83],{},"当我们需要准确的定义返回值的类型的时候，就需要泛型",[14,85,86],{},[42,87],{"alt":24,"src":88},"\u002Fimages\u002Ftypescript\u002Fts-9\u002Fts_9_02.png",[14,90,91],{},"这时候你可能会说，做类型收窄不就行了吗？就像下面这样",[18,93,96],{"className":94,"code":95,"language":36,"meta":24},[34],"function echo(whatever: number | string | boolean) {\n  switch (typeof whatever) {\n    case 'number':\n      return whatever;\n    case 'string':\n      return whatever;\n    case 'boolean':\n      return whatever;\n  }\n}\n",[26,97,95],{"__ignoreMap":24},[14,99,100],{},"但是你会发现，这样写得到的返回值类型是不准确的",[18,102,105],{"className":103,"code":104,"language":36,"meta":24},[34],"const a = echo(233);\n\u002F\u002F 我们期望 a 的类型是 233\n\u002F\u002F 但 a 的类型却是 string | number | boolean\n",[26,106,104],{"__ignoreMap":24},[14,108,109],{},"这时候，泛型就派上用场了",[18,111,114],{"className":112,"code":113,"language":36,"meta":24},[34],"function echo\u003CT>(whatever: T): T {\n  return whatever;\n}\n\nconst a = echo(233);\n\u002F\u002F a 的类型为 233\n",[26,115,113],{"__ignoreMap":24},[10,117,118],{"id":118},"简单泛型示例",[18,120,123],{"className":121,"code":122,"language":36,"meta":24},[34],"type Union\u003CA, B> = A | B;\ntype Union3\u003CA, B, C> = A | B | C;\ntype Intersect\u003CA, B> = A & B;\ntype Intersect3\u003CA, B, C> = A & B & C;\ninterface List\u003CA> {\n  [index: number]: A;\n}\ninterface Hash\u003CV> {\n  [key: string]: V;\n}\n",[26,124,122],{"__ignoreMap":24},[10,126,128],{"id":127},"条件类型conditional-types","条件类型（Conditional Types）",[14,130,131],{},[42,132],{"alt":24,"src":133},"\u002Fimages\u002Ftypescript\u002Fts-9\u002Fts_9_03.png",[14,135,136,139,140,143,144,147,148,151],{},[26,137,138],{"code":138},"T extends string"," 可理解为 ",[26,141,142],{"code":142},"T \u003C= string","（",[26,145,146],{"code":146},"T"," 包含于 ",[26,149,150],{"code":150},"string","）",[18,153,156],{"className":154,"code":155,"language":36,"meta":24},[34],"type R1 = LikeString\u003C'hi'> \u002F\u002F true\ntype R2 = LikeString\u003Ctrue> \u002F\u002F false\ntype S1 = LikeNumber\u003C2333> \u002F\u002F 1\ntype S2 = LikeNumber\u003Cfalse> \u002F\u002F 2\ntype T1 = LikePerson\u003C{ name: 'ClariS', age: 18 }> \u002F\u002F yes\ntype T2 = LikePerson\u003C{ age: 1 }> \u002F\u002F no\n",[26,157,155],{"__ignoreMap":24},[46,159,160],{},[14,161,162],{},"泛型中的特殊运算规则",[14,164,165,166],{},"现有如下泛型 ",[26,167,168],{"code":168},"ToArray",[18,170,173],{"className":171,"code":172,"language":36,"meta":24},[34],"type ToArray\u003CT> = T extends unknown ? T[] : never;\n",[26,174,172],{"__ignoreMap":24},[14,176,177,178,181],{},"问：",[26,179,180],{"code":180},"type Result = ToArray\u003Cstring | number>"," 的类型是什么？",[14,183,184,185,188,189],{},"直接说答案：",[26,186,187],{"code":187},"Result"," 为 ",[26,190,191],{"code":191},"string[] | number[]",[14,193,194,195,198,199,202,203,205,206,209],{},"你可能会疑惑，按照一般的理解，",[26,196,197],{"code":197},"string | number"," 是包含于 ",[26,200,201],{"code":201},"unknown"," 的，那么 ",[26,204,187],{"code":187}," 就应该是 ",[26,207,208],{"code":208},"(string | number)[]"," 呀",[14,211,212],{},"按照通常的理解是没错，但因为这是在泛型中，因此规则会有些许不同",[14,214,215],{},"可以按照如下拆分过程来进行理解记忆：",[18,217,220],{"className":218,"code":219,"language":36,"meta":24},[34],"type Result = ToArray\u003Cstring | number>;\n\u002F\u002F type Result = (string | number) extends unknown ? ...\n\u002F\u002F type Result = (string extends unknown ? ...) | (number extends unknown ? ...)\n\u002F\u002F type Result = string[] | number[]\n",[26,221,219],{"__ignoreMap":24},[14,223,224,225,143,228,231,232],{},"即泛型中的联合类型",[55,226,227],{},"会分开进行运算",[26,229,230],{"code":230},"extends"," 运算），这就好像是乘法中的分配率 ",[26,233,234],{"code":234},"(A + B) X C = A X C + B X C",[14,236,237,238,181],{},"再问：",[26,239,240],{"code":240},"type Result2 = ToArray\u003Cnever>",[14,242,243,244],{},"答案是 ",[26,245,246],{"code":246},"never",[14,248,249,250,198,252,202,254,256,257,260],{},"同样按照一般的理解，通常情况下（非泛型中），",[26,251,246],{"code":246},[26,253,201],{"code":201},[26,255,187],{"code":187}," 应该是 ",[26,258,259],{"code":259},"never[]"," 才对",[14,262,263,264,266,267],{},"但 ",[26,265,187],{"code":187}," 在此处却为 ",[26,268,246],{"code":246},[18,270,273],{"className":271,"code":272,"language":36,"meta":24},[34],"type Result = ToArray\u003Cnever>; \u002F\u002F never\n",[26,274,272],{"__ignoreMap":24},[14,276,277,278,280,281,283,284,287,288,290,291],{},"即泛型中的 ",[26,279,246],{"code":246}," 进行任何运算（",[26,282,230],{"code":230}," 运算或者 ",[26,285,286],{"code":286},"&"," 运算）都只会得到 ",[26,289,246],{"code":246},"，这就好像是乘法中的零 ",[26,292,293],{"code":293},"0 X C = 0",[295,296,298],"alert",{"type":297},"info",[14,299,300],{},"注意：以上讨论的规则只对泛型有效",[14,302,303,304,306],{},"在非泛型中，使用 ",[26,305,230],{"code":230}," 运算会得到不一样的结果",[18,308,311],{"className":309,"code":310,"language":36,"meta":24},[34],"\u002F\u002F 非泛型\ntype T0 = never extends never ? true : false\n\u002F\u002F   ^? type T0 = true\n\n\u002F\u002F 泛型\ntype IsNever\u003CT> = T extends never ? true : false\ntype T1 = IsNever\u003Cnever>\n\u002F\u002F   ^? type T1 = never\n",[26,312,310],{"__ignoreMap":24},[14,314,315,316,319],{},"那么，如何才能",[55,317,318],{},"禁用","泛型中的自动拆分规则呢？",[14,321,322,323,325,326],{},"我们可以构造一个类型，在外面包裹上一个新的类型来防止 TypeScript 遍历 ",[26,324,230],{"code":230}," 左侧类型的行为，比如下面的 ",[26,327,328],{"code":328},"[]",[18,330,333],{"className":331,"code":332,"language":36,"meta":24},[34],"type IsNever\u003CT> = [T] extends [never] ? true : false\ntype T0 = IsNever\u003Cnever>\n\u002F\u002F   ^? type T0 = true\n\ntype ToArray\u003CT> = [T] extends unknown ? T[] : never;\ntype Result1 = ToArray\u003Cstring | number>;\n\u002F\u002F   ^? type Result1 = (string | number)[]\ntype Result2 = ToArray\u003Cnever>;\n\u002F\u002F   ^? type Result2 = never[]\n",[26,334,332],{"__ignoreMap":24},[10,336,338],{"id":337},"在泛型中使用-keyof","在泛型中使用 keyof",[14,340,341,344,345],{},[26,342,343],{"code":343},"keyof"," 关键字用于获取",[55,346,347],{},"对象类型的所有键的联合类型",[18,349,352],{"className":350,"code":351,"language":36,"meta":24},[34],"type Person = { name: string; age: number };\ntype GetKeys\u003CT> = keyof T;\ntype Result = GetKeys\u003CPerson>;\n\u002F\u002F     ^-- 'name' | 'age'\n",[26,353,351],{"__ignoreMap":24},[14,355,356],{},"常和映射类型一起使用",[18,358,361],{"className":359,"code":360,"language":36,"meta":24},[34],"type Readonly\u003CT> = {\n  readonly [K in keyof T]: T[K];\n};\n",[26,362,360],{"__ignoreMap":24},[14,364,365,367],{},[26,366,343],{"code":343}," 也可用于数组 \u002F 元组",[18,369,372],{"className":370,"code":371,"language":36,"meta":24},[34],"type A = keyof [1, 2, 3];\n\u002F\u002F A 的类型为 \"0\" | \"1\" | \"2\" | \"length\" | \"toString\" | \"pop\" | ...\n",[26,373,371],{"__ignoreMap":24},[10,375,377],{"id":376},"在泛型中使用-extends-keyof","在泛型中使用 extends keyof",[18,379,382],{"className":380,"code":381,"language":36,"meta":24},[34],"type Person = { name: string; age: number };\ntype GetKeyType\u003CT, K extends keyof T> = T[K];\ntype Result1 = GetKeyType\u003CPerson, 'name'>; \u002F\u002F string\ntype Result2 = GetKeyType\u003CPerson, 'age'>; \u002F\u002F number\ntype Result3 = GetKeyType\u003CPerson, 'name' | 'age'>; \u002F\u002F string | number\n",[26,383,381],{"__ignoreMap":24},[14,385,386,389,390,393,394,397,398,401,402],{},[26,387,388],{"code":388},"K extends keyof T"," 的写法称为",[55,391,392],{},"泛型约束","，",[26,395,396],{"code":396},"GetKeyType"," 第二个参数 ",[26,399,400],{"code":400},"k"," 的类型必须包含于 ",[26,403,197],{"code":197},[10,405,406],{"id":406},"其他",[408,409,411],"h3",{"id":410},"propertykey","PropertyKey",[14,413,414,416,417,420],{},[26,415,411],{"code":411}," 是 TS 中的一个内置类型，它表示可以用作对象属性键的类型。它是 ",[26,418,419],{"code":419},"string | number | symbol"," 类型的别名，因为这些类型都可以用作对象属性的键。",[14,422,423,425,426,428,429,432,433,436,437,439,440,443,444,447],{},[26,424,411],{"code":411}," 类型常用于",[55,427,392],{},"，以确保泛型类型参数只能是可以用作对象属性键的类型。例如，定义一个泛型类型 ",[26,430,431],{"code":431},"Foo\u003CK extends PropertyKey>","，其中 ",[26,434,435],{"code":435},"K"," 只能是 ",[26,438,150],{"code":150},"、",[26,441,442],{"code":442},"number"," 或 ",[26,445,446],{"code":446},"symbol"," 类型。",[408,449,451],{"id":450},"tnumber","T[number]",[18,453,456],{"className":454,"code":455,"language":36,"meta":24},[34],"type A = [1, 2, 3]\ntype B = A[number] \u002F\u002F 3 | 1 | 2，无序\n",[26,457,455],{"__ignoreMap":24},[14,459,460,463,464,467,468,470,471],{},[26,461,462],{"code":462},"A[number]"," 表示获取类型 ",[26,465,466],{"code":466},"A"," 的数字索引签名的类型。由于元组类型具有隐式的数字索引签名，因此 ",[26,469,462],{"code":462}," 的类型为元组中所有元素类型的联合类型 ",[26,472,473],{"code":473},"1 | 2 | 3",{"title":24,"searchDepth":475,"depth":475,"links":476},4,[477,479,480,481,482,483,484],{"id":12,"depth":478,"text":12},2,{"id":80,"depth":478,"text":80},{"id":118,"depth":478,"text":118},{"id":127,"depth":478,"text":128},{"id":337,"depth":478,"text":338},{"id":376,"depth":478,"text":377},{"id":406,"depth":478,"text":406,"children":485},[486,488],{"id":410,"depth":487,"text":411},3,{"id":450,"depth":487,"text":451},[490,491],"学习笔记","TypeScript","2023-02-06",false,"md",null,{"comments":493,"slots":497},{},true,"\u002F2023\u002Ftypescript\u002Fts-9",{"text":501,"minutes":502,"time":503,"words":504},"7 min read",6.22,373200,1244,{"title":5,"description":24},{"loc":499,"images":507},[508,509,510],{"loc":44},{"loc":88},{"loc":133},"posts\u002F2023\u002Ftypescript\u002Fts-9",[491,30],"tech","w97CYEtw_dtUzmPG37XP6KVtv9uoFOLbBPF48QvY1SE",[516,521],{"title":517,"path":518,"stem":519,"date":520,"type":513,"children":-1},"深入函数：函数重载、this 和 as const","\u002F2023\u002Ftypescript\u002Fts-8","posts\u002F2023\u002Ftypescript\u002Fts-8","2023-02-03",{"title":522,"path":523,"stem":524,"date":525,"type":513,"children":-1},"泛型编程（下）","\u002F2023\u002Ftypescript\u002Fts-10","posts\u002F2023\u002Ftypescript\u002Fts-10","2023-02-07",1793699839262]