[{"data":1,"prerenderedAt":389},["ShallowReactive",2],{"content:\u002F2023\u002Ftypescript\u002Fts-8":3,"surround:\u002F2023\u002Ftypescript\u002Fts-8":378},{"id":4,"title":5,"body":6,"categories":352,"date":355,"description":25,"draft":356,"extension":357,"image":358,"meta":359,"navigation":361,"path":362,"permalink":358,"published":358,"readingTime":363,"recommend":358,"references":368,"seo":371,"sitemap":372,"stem":373,"tags":374,"type":376,"updated":358,"__hash__":377},"content\u002Fposts\u002F2023\u002Ftypescript\u002Fts-8.md","深入函数：函数重载、this 和 as const",{"type":7,"value":8,"toc":336},"minimark",[9,14,18,29,32,62,66,69,77,83,86,90,96,99,105,111,114,120,124,129,148,154,163,169,172,206,216,221,228,235,241,244,250,259,266,271,283,286,306,310,313,319,326,330],[10,11,13],"h2",{"id":12},"函数重载overload","函数重载（overload）",[15,16,17],"p",{},"重载允许一个函数在接受不同数量或类型的参数时，作出不同的处理",[19,20,26],"pre",{"className":21,"code":23,"language":24,"meta":25},[22],"language-ts","function createDate(n: number): Date;\nfunction createDate(year: number, month: number, date: number): Date;\n\n\u002F\u002F 中间不能写其他代码，函数类型声明后面只能接函数的实现\n\nfunction createDate(a: number, b?: number, c?: number): Date {\n  if (a !== undefined && b !== undefined && c !== undefined) {\n    return new Date(a, b, c);\n  } else if (a !== undefined && b === undefined && c === undefined) {\n    return new Date(a);\n  } else {\n    throw new Error('传参错误');\n  }\n}\n\ncreateDate(1677772800000);\ncreateDate(2023, 2, 3);\n","ts","",[27,28,23],"code",{"__ignoreMap":25},[15,30,31],{},"关于函数重载：",[33,34,35,39,42,51,54],"ul",{},[36,37,38],"li",{},"重载的思想来自于 Java 或 C#，因为它们都不支持联合类型",[36,40,41],{},"重载是为了使同名函数可以接受不同类型的参数",[36,43,44,45],{},"不是非得使用重载，即使不用函数重载也可以实现上述的功能\n",[19,46,49],{"className":47,"code":48,"language":24,"meta":25},[22],"function createDateFromNumber(n: number): Date {\n  return new Date(n);\n}\nfunction createDateFromYMD(year: number, month: number, date: number): Date {\n  return new Date(year, month, date);\n}\n\ncreateDateFromNumber(1677772800000);\ncreateDateFromYMD(2023, 2, 3);\n",[27,50,48],{"__ignoreMap":25},[36,52,53],{},"复杂度守恒，你不可能把复杂度凭空抹除掉，因此你只能选择把复杂度留给自己或者抛给用户。比如上面的例子中，使用函数重载就是把复杂度留给自己；而提供两个函数供用户选择就是把复杂度留给用户。",[36,55,56,57,61],{},"箭头函数",[58,59,60],"strong",{},"不支持函数重载","，箭头函数是匿名函数，无法定义多个同名的箭头函数，应该使用传统的函数声明或函数表达式。",[63,64,65],"h3",{"id":65},"举例",[15,67,68],{},"使用 TypeScript 的函数重载和类型谓词来处理具有不同属性的组件 props",[19,70,75],{"className":71,"code":73,"language":74,"meta":25},[72],"language-tsx","interface PropsA {\n  isA: true;\n  a1: boolean;\n  a2: string;\n  a3: number;\n}\n\ninterface PropsB {\n  isA: false;\n  b1: boolean;\n  b2: string;\n  b3: number;\n}\n\nfunction isPropsA(x: PropsA | PropsB): x is PropsA {\n  return x.isA;\n}\n\nexport function FunctionComponent(props: PropsA): JSX.Element;\nexport function FunctionComponent(props: PropsB): JSX.Element;\nexport function FunctionComponent(props: PropsA | PropsB) {\n  \u002F\u002F ...\n  if (isPropsA(props)) {\n    \u002F\u002F ...\n  } else {\n    \u002F\u002F ...\n  }\n}\n\n","tsx",[27,76,73],{"__ignoreMap":25},[19,78,81],{"className":79,"code":80,"language":74,"meta":25},[72],"\u002F\u002F isA 为 true 时，props 类型为 PropsA，a1、a2、a3 都必传\n\u003CFunctionComponent isA={true} a1={true} a2=\"hello\" a3={123} \u002F>\n\u002F\u002F isA 为 false 时，props 类型为 PropsB，b1、b2、b3 都必传\n\u003CFunctionComponent isA={false} b1={true} b2=\"world\" b3={456} \u002F>\n",[27,82,80],{"__ignoreMap":25},[15,84,85],{},"这种模式允许你在同一个组件中安全地处理不同的属性集，同时保持类型的严格性和清晰性。",[10,87,89],{"id":88},"指定-this-的类型","指定 this 的类型",[19,91,94],{"className":92,"code":93,"language":24,"meta":25},[22],"type Person = { name: string };\nfunction f(this: Person, n: number) {\n  console.log(this.name + n);\n}\n\n\u002F\u002F 1. person.f(1)\nconst p: Person & { f: typeof f } = { name: 'ClariS', f };\np.f(1);\n\u002F\u002F 2. f.call(person, 1)\nconst p2: Person = { name: 'ClariS' };\nf.call(p2, 1);\n\u002F\u002F 3. f.apply(person, [1])\nconst p3: Person = { name: 'ClariS' };\nf.apply(p3, [1]);\n\u002F\u002F 4. f.bind(person)(1)\nconst p4: Person = { name: 'ClariS' };\nconst newF = f.bind(p4);\nnewF(1);\n\u002F\u002F 或\nnewF.bind(null, 1);\n",[27,95,93],{"__ignoreMap":25},[10,97,98],{"id":98},"剩余参数",[19,100,103],{"className":101,"code":102,"language":24,"meta":25},[22],"function sum(name: string, ...array: number[]) {\n  console.log(name);\n  return array.reduce((result, n) => result + n, 0);\n}\nsum('one', 1);\nsum('two', 1, 2);\nsum('three', 1, 2, 3);\n",[27,104,102],{"__ignoreMap":25},[106,107,108],"blockquote",{},[15,109,110],{},"注意，剩余参数只能是最后一个参数",[10,112,113],{"id":113},"展开参数",[19,115,118],{"className":116,"code":117,"language":24,"meta":25},[22],"function sum(...array: number[]) {\n  f.apply(null, array);\n  \u002F\u002F f(array[0], array[1], array[2], array[3], ...)\n  f(...array);\n}\nfunction f(...array: number[]) {\n  console.log(array);\n}\n",[27,119,117],{"__ignoreMap":25},[10,121,123],{"id":122},"常量断言as-const","常量断言（as const）",[106,125,126],{},[15,127,128],{},"TS 会区别对待可修改和不可修改的值的类型推断",[15,130,131,132,135,136,139,140,143,144,147],{},"例如下面的 ",[27,133,134],{"code":134},"immutableString"," 会被推断成单值类型 ",[27,137,138],{"code":138},"'ClariS'"," 而 ",[27,141,142],{"code":142},"mutableString"," 则会被推断成通用的 ",[27,145,146],{"code":146},"string"," 类型",[19,149,152],{"className":150,"code":151,"language":24,"meta":25},[22],"const immutableString = 'ClariS'; \u002F\u002F 'ClariS'\nlet mutableString = 'vivy'; \u002F\u002F string\n",[27,153,151],{"__ignoreMap":25},[15,155,156,157,160,161],{},"而在一般的对象中，由于对象的属性都具有可修改性，TS 都会对它们「从宽」类型推断，例如下面的 ",[27,158,159],{"code":159},"prop"," 的类型被推断为 ",[27,162,146],{"code":146},[19,164,167],{"className":165,"code":166,"language":24,"meta":25},[22],"const obj = {\n  prop: 'xxx' \u002F\u002F string\n};\n",[27,168,166],{"__ignoreMap":25},[15,170,171],{},"根本原因在于 TS 会根据一个值在后续的逻辑中是否可能被修改而给出不同的类型推断结果：",[33,173,174,191],{},[36,175,176,177,180,181,183,184,187,188,190],{},"对于",[58,178,179],{},"有可能被修改","的值，TS 采用较为宽松的类型推断策略，即把上述 ",[27,182,142],{"code":142},"，",[27,185,186],{"code":186},"obj.props"," 推断为较为宽泛的 ",[27,189,146],{"code":146}," 类型，这使未来可能出现的赋值具有更大的灵活度",[36,192,176,193,196,197,199,200,202,203,205],{},[58,194,195],{},"不可能被重新赋值","的值，TS 采用较为严格的类型推断策略，即把上述 ",[27,198,134],{"code":134}," 推断为单值类型 ",[27,201,138],{"code":138},"，这样未来把",[27,204,134],{"code":134}," 赋值给别的变量时，出现类型检查错误的可能性更小",[15,207,208,209],{},"关于这部分内容，详细可参考文章",[210,211,215],"a",{"href":212,"rel":213},"https:\u002F\u002Fjuejin.cn\u002Fpost\u002F6844904068029104136",[214],"nofollow","TypeScript夜点心：类型推断的策略",[106,217,218],{},[15,219,220],{},"TS 常量断言",[15,222,223,224,227],{},"常量断言可以把一个值标记为一个",[58,225,226],{},"不可篡改","的常量，从而让 TS 以最严格的策略来进行类型推断",[15,229,230,231,234],{},"还是使用上述的例子，给他们分别加上 ",[27,232,233],{"code":233},"as const"," 后类型推断如下",[19,236,239],{"className":237,"code":238,"language":24,"meta":25},[22],"let mutableString = 'vivy' as const; \u002F\u002F 'vivy'\n\nconst obj = {\n  prop: 'xxx' as const \u002F\u002F 'xxx'\n};\n",[27,240,238],{"__ignoreMap":25},[15,242,243],{},"再看看其他的例子",[19,245,248],{"className":246,"code":247,"language":24,"meta":25},[22],"const array1 = [1, 'hi']; \u002F\u002F (string | number)[]\narray1.push(2); \u002F\u002F 不报错\n\nconst array2 = [1, 'hi'] as const; \u002F\u002F readonly [1, \"hi\"]\narray2.push(2); \u002F\u002F 报错\n",[27,249,247],{"__ignoreMap":25},[15,251,252,253,255,256],{},"从以上例子中可以看出，",[27,254,233],{"code":233}," 会把类型推窄，并给类型加上 ",[27,257,258],{"code":258},"readonly",[15,260,208,261],{},[210,262,265],{"href":263,"rel":264},"https:\u002F\u002Fjuejin.cn\u002Fpost\u002F6844904110588690439",[214],"TypeScript 夜点心：常量断言",[106,267,268],{},[15,269,270],{},"const 与 as const 的区别",[15,272,273,275,276,279,280,282],{},[27,274,233],{"code":233}," 中的 ",[27,277,278],{"code":278},"const"," 与我们声明常量时使用的 ",[27,281,278],{"code":278}," 有什么区别呢？",[15,284,285],{},"其实两者无论是语法还是语义，都相当不同：",[33,287,288,297],{},[36,289,290,292,293,296],{},[27,291,278],{"code":278}," 常量声明是 ES6 的语法，对 TS 而言，它只能反映该常量本身是不可被重新赋值的，",[58,294,295],{},"它的子属性仍然可以被修改","，故 TS 只会对它们做松散的类型推断",[36,298,299,301,302,305],{},[27,300,233],{"code":233}," 是 TS 的语法，它告诉 TS ",[58,303,304],{},"它所断言的值以及该值的所有层级的子属性都是不可篡改的","，故对每一级子属性都会做最严格的类型推断",[10,307,309],{"id":308},"more-about-the-function","more about the function",[63,311,312],{"id":312},"完整示例",[19,314,317],{"className":315,"code":316,"language":24,"meta":25},[22],"type Config = {\n  url: string;\n  method: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n  data?: unknown;\n  headers?: unknown;\n};\n\nfunction ajax1({ url, method, ...rest }: Config = { method: 'GET', url: '' }) {\n  console.log(url, method, rest);\n}\n\nfunction ajax2({ url, method, ...rest } = { method: 'GET', url: '' } as Config) {\n  console.log(url, method, rest);\n}\n",[27,318,316],{"__ignoreMap":25},[15,320,321,322,325],{},"类型 ",[27,323,324],{"code":324},"Config"," 可以写在左边，也可以写在右边",[63,327,329],{"id":328},"void-返回值类型","void 返回值类型",[19,331,334],{"className":332,"code":333,"language":24,"meta":25},[22],"function f1(): void {\n  return;\n}\n\nfunction f2(): void {\n  return undefined;\n}\n\nfunction f3(): void {}\n\nfunction f4(): void {\n  return null; \u002F\u002F 报错：Type 'null' is not assignable to type 'void'\n}\n\ntype F5 = () => void;\nconst f5: F5 = () => {\n  return;\n};\n",[27,335,333],{"__ignoreMap":25},{"title":25,"searchDepth":337,"depth":337,"links":338},4,[339,344,345,346,347,348],{"id":12,"depth":340,"text":13,"children":341},2,[342],{"id":65,"depth":343,"text":65},3,{"id":88,"depth":340,"text":89},{"id":98,"depth":340,"text":98},{"id":113,"depth":340,"text":113},{"id":122,"depth":340,"text":123},{"id":308,"depth":340,"text":309,"children":349},[350,351],{"id":312,"depth":343,"text":312},{"id":328,"depth":343,"text":329},[353,354],"学习笔记","TypeScript","2023-02-03",false,"md",null,{"comments":356,"slots":360},{},true,"\u002F2023\u002Ftypescript\u002Fts-8",{"text":364,"minutes":365,"time":366,"words":367},"8 min read",7.325,439500,1465,[369,370],{"title":215,"link":212},{"title":265,"link":263},{"title":5,"description":25},{"loc":362},"posts\u002F2023\u002Ftypescript\u002Fts-8",[354,233,375],"函数重载","tech","GjPwJFrBF_tnwr-X-ix6i6jV6FhtbKxjlz4qEmTizTQ",[379,384],{"title":380,"path":381,"stem":382,"date":383,"type":376,"children":-1},"深入函数：声明、参数、返回值","\u002F2023\u002Ftypescript\u002Fts-7","posts\u002F2023\u002Ftypescript\u002Fts-7","2023-02-01",{"title":385,"path":386,"stem":387,"date":388,"type":376,"children":-1},"泛型编程（上）","\u002F2023\u002Ftypescript\u002Fts-9","posts\u002F2023\u002Ftypescript\u002Fts-9","2023-02-06",1793699839273]