[{"data":1,"prerenderedAt":331},["ShallowReactive",2],{"content:\u002F2023\u002Ftypescript\u002Fts-10":3,"surround:\u002F2023\u002Ftypescript\u002Fts-10":320},{"id":4,"title":5,"body":6,"categories":297,"date":300,"description":12,"draft":301,"extension":302,"image":303,"meta":304,"navigation":306,"path":307,"permalink":303,"published":303,"readingTime":308,"recommend":303,"references":303,"seo":313,"sitemap":314,"stem":315,"tags":316,"type":318,"updated":303,"__hash__":319},"content\u002Fposts\u002F2023\u002Ftypescript\u002Fts-10.md","泛型编程（下）",{"type":7,"value":8,"toc":284},"minimark",[9,13,18,29,32,51,55,61,68,72,78,87,93,103,107,113,153,157,163,167,173,177,183,192,223,227,233,254,257,265,268],[10,11,12],"p",{},"本文介绍了一些 TS 内置工具类型的用法及实现",[14,15,17],"h2",{"id":16},"readonly-mutable","Readonly & Mutable",[19,20,26],"pre",{"className":21,"code":23,"language":24,"meta":25},[22],"language-ts","type Person = { id: number; name: string; age: number };\n\ntype MyReadonly\u003CT> = {\n  readonly [K in keyof T]: T[K];\n};\ntype X1 = MyReadonly\u003CPerson>;\n\u002F\u002F {\n\u002F\u002F   readonly id: number;\n\u002F\u002F   readonly name: string;\n\u002F\u002F   readonly age: number;\n\u002F\u002F }\n\ntype MyMutable\u003CT> = {\n  -readonly [K in keyof T]: T[K];\n};\ntype X9 = MyMutable\u003CReadonly\u003CPerson>>;\n\u002F\u002F {\n\u002F\u002F   id: number;\n\u002F\u002F   name: string;\n\u002F\u002F   age: number;\n\u002F\u002F }\n","ts","",[27,28,23],"code",{"__ignoreMap":25},[10,30,31],{},"注意：",[33,34,35,42],"ul",{},[36,37,38,41],"li",{},[27,39,40],{"code":40},"Mutable"," 并不是 TS 内置的函数",[36,43,44,47,48],{},[27,45,46],{"code":46},"-readonly []"," 表示去掉属性前面的 ",[27,49,50],{"code":50},"Readonly",[14,52,54],{"id":53},"partial-required","Partial & Required",[19,56,59],{"className":57,"code":58,"language":24,"meta":25},[22],"type Person = { id: number; name: string; age: number };\n\ntype MyPartial\u003CT> = {\n  [K in keyof T]?: T[K];\n};\ntype X2 = MyPartial\u003CPerson>;\n\u002F\u002F {\n\u002F\u002F   id?: number;\n\u002F\u002F   name?: string;\n\u002F\u002F   age?: number;\n\u002F\u002F }\n\ntype MyRequired\u003CT> = {\n  [K in keyof T]-?: T[K];\n};\ntype X3 = MyRequired\u003CPerson>;\n\u002F\u002F {\n\u002F\u002F   id: number;\n\u002F\u002F   name: string;\n\u002F\u002F   age: number;\n\u002F\u002F }\n",[27,60,58],{"__ignoreMap":25},[10,62,63,64,67],{},"注意 ",[27,65,66],{"code":66},"-?","，表示去掉属性的可选，变为必选",[14,69,71],{"id":70},"exclude-extract","Exclude & Extract",[19,73,76],{"className":74,"code":75,"language":24,"meta":25},[22],"type MyExclude\u003CA, B> = A extends B ? never : A;\ntype X5 = Exclude\u003C1 | 2 | 3, 1 | 2>; \u002F\u002F 3\n\ntype MyExtract\u003CA, B> = A extends B ? A : never;\ntype X6 = MyExtract\u003C1 | 2 | 3, 2 | 4>; \u002F\u002F 2\n",[27,77,75],{"__ignoreMap":25},[10,79,80,81,86],{},"按照之前讲的",[82,83,85],"a",{"href":84},"\u002F2023\u002Ftypescript\u002Fts-9#%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8Bconditional-types","乘法分配律","，有如下理解过程：",[19,88,91],{"className":89,"code":90,"language":24,"meta":25},[22],"type X5 = 1 | 2 | 3 extends 1 | 2 ? never : A\n\ntype X5 = \n| 1 extends 1 | 2 ? never : 1 \u002F\u002F never\n| 2 extends 1 | 2 ? never : 2 \u002F\u002F never\n| 3 extends 1 | 2 ? never : 3 \u002F\u002F 3\n\ntype X5 = never | never | 3 \u002F\u002F 3\n",[27,92,90],{"__ignoreMap":25},[10,94,95,98,99,102],{},[27,96,97],{"code":97},"X6"," 的理解过程同 ",[27,100,101],{"code":101},"X5","，这里不赘述",[14,104,106],{"id":105},"omit-pick","Omit & Pick",[19,108,111],{"className":109,"code":110,"language":24,"meta":25},[22],"type Person = { id: number; name: string; age: number };\n\ntype MyOmit\u003CT, Key extends keyof T> = Pick\u003CT, Exclude\u003Ckeyof T, Key>>;\n\u002F\u002F 或者\ntype MyOmit\u003CT, Key extends keyof T> = {\n  [K2 in keyof T as (K2 extends Key ? never : K2)]: T[K2];\n};\ntype X7 = MyOmit\u003CPerson, 'name' | 'age'>; \u002F\u002F { id: number }\n\ntype MyPick\u003CT, Key extends keyof T> = {\n  [K2 in Key]: T[K2];\n};\ntype X8 = MyPick\u003CPerson, 'name' | 'age'>; \u002F\u002F { name: string; age: number }\n",[27,112,110],{"__ignoreMap":25},[33,114,115,133],{},[36,116,117,120,121,124,125,128,129,132],{},[27,118,119],{"code":119},"Key extends keyof T"," 是一个泛型约束，约束所传的 ",[27,122,123],{"code":123},"key"," 必须包含在 ",[27,126,127],{"code":127},"keyof T"," 中，即必须是 ",[27,130,131],{"code":131},"'id' | 'name' | 'age'"," 的子集",[36,134,135,138,139,142,143,146,147],{},[27,136,137],{"code":137},"MyOmit"," 的第二个写法中，集合 ",[27,140,141],{"code":141},"K2 extends Key ? never : K2"," 小于或等于集合 ",[27,144,145],{"code":145},"K2 in keyof T","，依旧遵循之前讲的类型兼容，类型小的可赋值给类型大的，",[82,148,152],{"href":149,"rel":150},"https:\u002F\u002Fgithub.com\u002Ftype-challenges\u002Ftype-challenges\u002Fissues\u002F28788",[151],"nofollow","查看实现思路",[14,154,156],{"id":155},"record","Record",[19,158,161],{"className":159,"code":160,"language":24,"meta":25},[22],"type MyRecord\u003CKey extends string | number | symbol, Value> = {\n  [k in Key]: Value;\n};\n\ntype X4 = MyRecord\u003Cstring, string>; \u002F\u002F { [x: string]: string }\n",[27,162,160],{"__ignoreMap":25},[14,164,166],{"id":165},"returntype","ReturnType",[19,168,171],{"className":169,"code":170,"language":24,"meta":25},[22],"type MyReturnType\u003CT extends (...args: any[]) => unknown> =\n  T extends (...args: any[]) => infer U\n  ? U\n  : never\n\nconst fn = (v: boolean) => {\n  if (v) return 1\n  else return 2\n}\n\ntype Result = MyReturnType\u003Ctypeof fn> \u002F\u002F 应推导出 \"1 | 2\"\n",[27,172,170],{"__ignoreMap":25},[14,174,176],{"id":175},"awaited","Awaited",[19,178,181],{"className":179,"code":180,"language":24,"meta":25},[22],"type MyAwaited\u003CT extends PromiseLike\u003Cany>> = T extends PromiseLike\u003Cinfer U>\n  ? U extends PromiseLike\u003Cany>\n  ? MyAwaited\u003CU>\n  : U\n  : never;\n\ntype Result = MyAwaited\u003CPromise\u003Cstring>> \u002F\u002F string\n",[27,182,180],{"__ignoreMap":25},[184,185,186,189],"blockquote",{},[10,187,188],{},"PromiseLike 表示一个对象具有 then 方法，它可以像 Promise 一样使用链式调用。",[10,190,191],{},"PromiseLike 可以表示内置的 Promise 对象和第三方库或自定义实现的 thenable 对象，因此 PromiseLike 提供了更广泛的兼容性。",[193,194,195,201,211,220],"ol",{},[36,196,197,198],{},"限制传入的类型必须是 ",[27,199,200],{"code":200},"PromiseLike",[36,202,203,204,207,208,210],{},"使用 ",[27,205,206],{"code":206},"infer"," 推导 ",[27,209,200],{"code":200}," 参数类型",[36,212,213,214,216,217],{},"如果推导类型仍为 ",[27,215,200],{"code":200},"，就循环调用 ",[27,218,219],{"code":219},"MyAwaited",[36,221,222],{},"否则直接返回推导类型",[14,224,226],{"id":225},"parameters","Parameters",[19,228,231],{"className":229,"code":230,"language":24,"meta":25},[22],"type MyParameters\u003CT extends (...args: any[]) => unknown> =\n  T extends (...args: infer P) => unknown\n  ? P\n  : never;\n\nconst foo = (arg1: string, arg2: number): void => {}\n\ntype Result = MyParameters\u003Ctypeof foo> \u002F\u002F [arg1: string, arg2: number]\n",[27,232,230],{"__ignoreMap":25},[193,234,235,238,243],{},[36,236,237],{},"限制传入的类型必须是函数类型",[36,239,203,240,242],{},[27,241,206],{"code":206}," 推导函数的参数类型",[36,244,245,246,249,250,253],{},"由于 ",[27,247,248],{"code":248},"...args"," 本身已经是元组类型，因此 ",[27,251,252],{"code":252},"infer P"," 最终推导出的，也是元组类型",[14,255,256],{"id":256},"其他",[10,258,259,260],{},"这里推荐一个用于练习 TS 类型体操的 repo：",[82,261,264],{"href":262,"rel":263},"https:\u002F\u002Fgithub.com\u002Ftype-challenges\u002Ftype-challenges\u002Fblob\u002Fmain\u002FREADME.zh-CN.md",[151],"TypeScript 类型体操姿势合集",[10,266,267],{},"看看别人的体操：",[33,269,270,277],{},[36,271,272],{},[82,273,276],{"href":274,"rel":275},"https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F426966480?utm_id=0#showWechatShareTip",[151],"用 TypeScript 类型运算实现一个中国象棋程序",[36,278,279],{},[82,280,283],{"href":281,"rel":282},"https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F427309936",[151],"TypeScript 类型体操天花板，用类型运算写一个 Lisp 解释器",{"title":25,"searchDepth":285,"depth":285,"links":286},4,[287,289,290,291,292,293,294,295,296],{"id":16,"depth":288,"text":17},2,{"id":53,"depth":288,"text":54},{"id":70,"depth":288,"text":71},{"id":105,"depth":288,"text":106},{"id":155,"depth":288,"text":156},{"id":165,"depth":288,"text":166},{"id":175,"depth":288,"text":176},{"id":225,"depth":288,"text":226},{"id":256,"depth":288,"text":256},[298,299],"学习笔记","TypeScript","2023-02-07",false,"md",null,{"comments":301,"slots":305},{},true,"\u002F2023\u002Ftypescript\u002Fts-10",{"text":309,"minutes":310,"time":311,"words":312},"5 min read",4.285,257100,857,{"title":5,"description":12},{"loc":307},"posts\u002F2023\u002Ftypescript\u002Fts-10",[299,317],"泛型","tech","t8_zC8v4Dqe2AuL7u0-SFOIwtZF9CJHXyETI2lqeT0c",[321,326],{"title":322,"path":323,"stem":324,"date":325,"type":318,"children":-1},"泛型编程（上）","\u002F2023\u002Ftypescript\u002Fts-9","posts\u002F2023\u002Ftypescript\u002Fts-9","2023-02-06",{"title":327,"path":328,"stem":329,"date":330,"type":318,"children":-1},"面向对象之原型","\u002F2023\u002Ftypescript\u002Fts-11","posts\u002F2023\u002Ftypescript\u002Fts-11","2023-02-09",1793699839251]