[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript":3677,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript":3703},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":3673,"stem":3674,"id":3675,"extension":3676},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript","TypeScript 深度集成","Vue 3 源码使用 TypeScript 编写， 可获得良好的类型推导。见 Vue 基础。","技能小册",[12,13],"vue","typescript","2023-11-29",false,{"type":17,"value":18,"toc":3660},"minimark",[19,23,38,45,50,56,60,218,225,231,393,396,431,487,501,505,512,799,802,887,891,898,902,1080,1083,1337,1344,1357,1530,1741,1950,1957,1964,2036,2139,2150,2154,2161,2165,2403,2406,2519,2523,2526,2735,2739,2786,2790,2793,2796,3022,3025,3322,3330,3340,3453,3457,3595,3598,3602,3605,3656],[20,21,8],"h1",{"id":22},"typescript-深度集成",[24,25,26,27,31,32,37],"p",{},"Vue 3 源码使用 TypeScript 编写，",[28,29,30],"code",{},"\u003Cscript setup lang=\"ts\">"," 可获得良好的类型推导。见 ",[33,34,36],"a",{"href":35},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fbasics","Vue 基础","。",[24,39,40,41,44],{},"Vue 3 采用 TypeScript 编写，天然提供了优秀的类型支持。组合式 API 加上 ",[28,42,43],{},"\u003Cscript setup>"," 语法糖，使得类型推导更加智能。下面从组件开发、依赖注入、全局扩展、状态管理、组合式函数等角度介绍最佳实践。",[46,47,49],"h3",{"id":48},"_1-组件-props-类型定义","1. 组件 Props 类型定义",[24,51,52,53,55],{},"在 ",[28,54,43],{}," 中，使用纯类型语法定义 props，无需运行时声明。",[57,58,59],"h4",{"id":59},"基本泛型语法",[61,62,66],"pre",{"className":63,"code":64,"language":12,"meta":65,"style":65},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","\u003Cscript setup lang=\"ts\">\n\u002F\u002F 编译时转换为运行时声明，同时提供类型\nconst props = defineProps\u003C{\n  title: string;\n  count: number;\n  visible?: boolean; \u002F\u002F 可选\n  tags: string[];\n}>();\n\u003C\u002Fscript>\n","",[28,67,68,104,111,133,150,163,181,197,208],{"__ignoreMap":65},[69,70,73,77,81,85,88,91,95,99,101],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"sP7_E","\u003C",[69,78,80],{"class":79},"sQzsp","script",[69,82,84],{"class":83},"s9AJx"," setup",[69,86,87],{"class":83}," lang",[69,89,90],{"class":75},"=",[69,92,94],{"class":93},"sjJ54","\"",[69,96,98],{"class":97},"s_sjI","ts",[69,100,94],{"class":93},[69,102,103],{"class":75},">\n",[69,105,107],{"class":71,"line":106},2,[69,108,110],{"class":109},"sutJx","\u002F\u002F 编译时转换为运行时声明，同时提供类型\n",[69,112,114,118,122,126,130],{"class":71,"line":113},3,[69,115,117],{"class":116},"sbsja","const",[69,119,121],{"class":120},"s_hVV"," props",[69,123,125],{"class":124},"smGrS"," =",[69,127,129],{"class":128},"sGLFI"," defineProps",[69,131,132],{"class":75},"\u003C{\n",[69,134,136,140,143,147],{"class":71,"line":135},4,[69,137,139],{"class":138},"sucvu","  title",[69,141,142],{"class":124},":",[69,144,146],{"class":145},"sZMiF"," string",[69,148,149],{"class":75},";\n",[69,151,153,156,158,161],{"class":71,"line":152},5,[69,154,155],{"class":138},"  count",[69,157,142],{"class":124},[69,159,160],{"class":145}," number",[69,162,149],{"class":75},[69,164,166,169,172,175,178],{"class":71,"line":165},6,[69,167,168],{"class":138},"  visible",[69,170,171],{"class":124},"?:",[69,173,174],{"class":145}," boolean",[69,176,177],{"class":75},";",[69,179,180],{"class":109}," \u002F\u002F 可选\n",[69,182,184,187,189,191,195],{"class":71,"line":183},7,[69,185,186],{"class":138},"  tags",[69,188,142],{"class":124},[69,190,146],{"class":145},[69,192,194],{"class":193},"su5hD","[]",[69,196,149],{"class":75},[69,198,200,203,206],{"class":71,"line":199},8,[69,201,202],{"class":75},"}>",[69,204,205],{"class":193},"()",[69,207,149],{"class":75},[69,209,211,214,216],{"class":71,"line":210},9,[69,212,213],{"class":75},"\u003C\u002F",[69,215,80],{"class":79},[69,217,103],{"class":75},[57,219,221,224],{"id":220},"withdefaults-提供默认值",[28,222,223],{},"withDefaults"," 提供默认值",[24,226,227,228,230],{},"当需要默认值时，使用 ",[28,229,223],{}," 编译器宏：",[61,232,234],{"className":63,"code":233,"language":12,"meta":65,"style":65},"\u003Cscript setup lang=\"ts\">\nexport interface Props {\n  title: string;\n  count?: number;\n  disabled?: boolean;\n}\n\nconst props = withDefaults(defineProps\u003CProps>(), {\n  count: 0,\n  disabled: false,\n});\n\u003C\u002Fscript>\n",[28,235,236,256,272,282,292,303,308,314,346,360,373,384],{"__ignoreMap":65},[69,237,238,240,242,244,246,248,250,252,254],{"class":71,"line":72},[69,239,76],{"class":75},[69,241,80],{"class":79},[69,243,84],{"class":83},[69,245,87],{"class":83},[69,247,90],{"class":75},[69,249,94],{"class":93},[69,251,98],{"class":97},[69,253,94],{"class":93},[69,255,103],{"class":75},[69,257,258,262,265,269],{"class":71,"line":106},[69,259,261],{"class":260},"sVHd0","export",[69,263,264],{"class":116}," interface",[69,266,268],{"class":267},"sbgvK"," Props",[69,270,271],{"class":75}," {\n",[69,273,274,276,278,280],{"class":71,"line":113},[69,275,139],{"class":138},[69,277,142],{"class":124},[69,279,146],{"class":145},[69,281,149],{"class":75},[69,283,284,286,288,290],{"class":71,"line":135},[69,285,155],{"class":138},[69,287,171],{"class":124},[69,289,160],{"class":145},[69,291,149],{"class":75},[69,293,294,297,299,301],{"class":71,"line":152},[69,295,296],{"class":138},"  disabled",[69,298,171],{"class":124},[69,300,174],{"class":145},[69,302,149],{"class":75},[69,304,305],{"class":71,"line":165},[69,306,307],{"class":75},"}\n",[69,309,310],{"class":71,"line":183},[69,311,313],{"emptyLinePlaceholder":312},true,"\n",[69,315,316,318,320,322,325,328,331,333,336,339,341,344],{"class":71,"line":199},[69,317,117],{"class":116},[69,319,121],{"class":120},[69,321,125],{"class":124},[69,323,324],{"class":128}," withDefaults",[69,326,327],{"class":193},"(",[69,329,330],{"class":128},"defineProps",[69,332,76],{"class":75},[69,334,335],{"class":267},"Props",[69,337,338],{"class":75},">",[69,340,205],{"class":193},[69,342,343],{"class":75},",",[69,345,271],{"class":75},[69,347,348,351,353,357],{"class":71,"line":210},[69,349,155],{"class":350},"skxfh",[69,352,142],{"class":75},[69,354,356],{"class":355},"srdBf"," 0",[69,358,359],{"class":75},",\n",[69,361,363,365,367,371],{"class":71,"line":362},10,[69,364,296],{"class":350},[69,366,142],{"class":75},[69,368,370],{"class":369},"syTEX"," false",[69,372,359],{"class":75},[69,374,376,379,382],{"class":71,"line":375},11,[69,377,378],{"class":75},"}",[69,380,381],{"class":193},")",[69,383,149],{"class":75},[69,385,387,389,391],{"class":71,"line":386},12,[69,388,213],{"class":75},[69,390,80],{"class":79},[69,392,103],{"class":75},[57,394,395],{"id":395},"复杂类型",[397,398,399,410,423],"ul",{},[400,401,402,406,407],"li",{},[403,404,405],"strong",{},"联合类型","：",[28,408,409],{},"status: 'loading' | 'success' | 'error'",[400,411,412,415,416,419,420],{},[403,413,414],{},"接口引用","：先定义 ",[28,417,418],{},"interface User { name: string; age: number }","，然后 ",[28,421,422],{},"user: User",[400,424,425,406,428],{},[403,426,427],{},"函数类型 props",[28,429,430],{},"onClick?: (value: string) => void",[61,432,435],{"className":433,"code":434,"language":98,"meta":65,"style":65},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","defineProps\u003C{\n  onSubmit: (data: FormData) => Promise\u003Cvoid>;\n}>();\n",[28,436,437,443,479],{"__ignoreMap":65},[69,438,439,441],{"class":71,"line":72},[69,440,330],{"class":128},[69,442,132],{"class":75},[69,444,445,449,451,454,458,460,463,465,468,471,473,476],{"class":71,"line":106},[69,446,448],{"class":447},"sVXei","  onSubmit",[69,450,142],{"class":124},[69,452,453],{"class":75}," (",[69,455,457],{"class":456},"s99_P","data",[69,459,142],{"class":124},[69,461,462],{"class":267}," FormData",[69,464,381],{"class":75},[69,466,467],{"class":116}," =>",[69,469,470],{"class":267}," Promise",[69,472,76],{"class":75},[69,474,475],{"class":145},"void",[69,477,478],{"class":75},">;\n",[69,480,481,483,485],{"class":71,"line":113},[69,482,202],{"class":75},[69,484,205],{"class":193},[69,486,149],{"class":75},[24,488,489,492,493,496,497,500],{},[403,490,491],{},"注意","：类型仅用于编译时，运行时 props 验证依然由 Vue 处理（通过 ",[28,494,495],{},"runtimeProps"," 转换）。如果需要在运行时检查复杂类型，可搭配 ",[28,498,499],{},"validator","，但类型系统本身已足够。",[46,502,504],{"id":503},"_2-组件-emits-类型定义","2. 组件 Emits 类型定义",[24,506,507,508,511],{},"使用 ",[28,509,510],{},"defineEmits"," 并标注事件签名，可以获得类型提示和校验。",[61,513,515],{"className":63,"code":514,"language":12,"meta":65,"style":65},"\u003Cscript setup lang=\"ts\">\nconst emit = defineEmits\u003C{\n  (e: \"change\", value: string): void;\n  (e: \"update\", id: number, payload: Record\u003Cstring, any>): void;\n  (e: \"click\", event: MouseEvent): void;\n}>();\n\n\u002F\u002F 调用时自动推导参数类型\nemit(\"change\", \"hello\"); \u002F\u002F ✅\nemit(\"update\", 1, { a: 1 }); \u002F\u002F ✅\nemit(\"click\", new MouseEvent(\"click\")); \u002F\u002F ✅\n\u003C\u002Fscript>\n",[28,516,517,537,551,587,640,673,681,685,690,719,757,791],{"__ignoreMap":65},[69,518,519,521,523,525,527,529,531,533,535],{"class":71,"line":72},[69,520,76],{"class":75},[69,522,80],{"class":79},[69,524,84],{"class":83},[69,526,87],{"class":83},[69,528,90],{"class":75},[69,530,94],{"class":93},[69,532,98],{"class":97},[69,534,94],{"class":93},[69,536,103],{"class":75},[69,538,539,541,544,546,549],{"class":71,"line":106},[69,540,117],{"class":116},[69,542,543],{"class":120}," emit",[69,545,125],{"class":124},[69,547,548],{"class":128}," defineEmits",[69,550,132],{"class":75},[69,552,553,556,559,561,564,567,569,571,574,576,578,580,582,585],{"class":71,"line":113},[69,554,555],{"class":75},"  (",[69,557,558],{"class":456},"e",[69,560,142],{"class":124},[69,562,563],{"class":93}," \"",[69,565,566],{"class":97},"change",[69,568,94],{"class":93},[69,570,343],{"class":75},[69,572,573],{"class":456}," value",[69,575,142],{"class":124},[69,577,146],{"class":145},[69,579,381],{"class":75},[69,581,142],{"class":124},[69,583,584],{"class":145}," void",[69,586,149],{"class":75},[69,588,589,591,593,595,597,600,602,604,607,609,611,613,616,618,621,623,626,628,631,634,636,638],{"class":71,"line":135},[69,590,555],{"class":75},[69,592,558],{"class":456},[69,594,142],{"class":124},[69,596,563],{"class":93},[69,598,599],{"class":97},"update",[69,601,94],{"class":93},[69,603,343],{"class":75},[69,605,606],{"class":456}," id",[69,608,142],{"class":124},[69,610,160],{"class":145},[69,612,343],{"class":75},[69,614,615],{"class":456}," payload",[69,617,142],{"class":124},[69,619,620],{"class":267}," Record",[69,622,76],{"class":75},[69,624,625],{"class":145},"string",[69,627,343],{"class":75},[69,629,630],{"class":145}," any",[69,632,633],{"class":75},">)",[69,635,142],{"class":124},[69,637,584],{"class":145},[69,639,149],{"class":75},[69,641,642,644,646,648,650,653,655,657,660,662,665,667,669,671],{"class":71,"line":152},[69,643,555],{"class":75},[69,645,558],{"class":456},[69,647,142],{"class":124},[69,649,563],{"class":93},[69,651,652],{"class":97},"click",[69,654,94],{"class":93},[69,656,343],{"class":75},[69,658,659],{"class":456}," event",[69,661,142],{"class":124},[69,663,664],{"class":267}," MouseEvent",[69,666,381],{"class":75},[69,668,142],{"class":124},[69,670,584],{"class":145},[69,672,149],{"class":75},[69,674,675,677,679],{"class":71,"line":165},[69,676,202],{"class":75},[69,678,205],{"class":193},[69,680,149],{"class":75},[69,682,683],{"class":71,"line":183},[69,684,313],{"emptyLinePlaceholder":312},[69,686,687],{"class":71,"line":199},[69,688,689],{"class":109},"\u002F\u002F 调用时自动推导参数类型\n",[69,691,692,695,697,699,701,703,705,707,710,712,714,716],{"class":71,"line":210},[69,693,694],{"class":128},"emit",[69,696,327],{"class":193},[69,698,94],{"class":93},[69,700,566],{"class":97},[69,702,94],{"class":93},[69,704,343],{"class":75},[69,706,563],{"class":93},[69,708,709],{"class":97},"hello",[69,711,94],{"class":93},[69,713,381],{"class":193},[69,715,177],{"class":75},[69,717,718],{"class":109}," \u002F\u002F ✅\n",[69,720,721,723,725,727,729,731,733,736,738,741,744,746,748,751,753,755],{"class":71,"line":362},[69,722,694],{"class":128},[69,724,327],{"class":193},[69,726,94],{"class":93},[69,728,599],{"class":97},[69,730,94],{"class":93},[69,732,343],{"class":75},[69,734,735],{"class":355}," 1",[69,737,343],{"class":75},[69,739,740],{"class":75}," {",[69,742,743],{"class":350}," a",[69,745,142],{"class":75},[69,747,735],{"class":355},[69,749,750],{"class":75}," }",[69,752,381],{"class":193},[69,754,177],{"class":75},[69,756,718],{"class":109},[69,758,759,761,763,765,767,769,771,774,776,778,780,782,784,787,789],{"class":71,"line":375},[69,760,694],{"class":128},[69,762,327],{"class":193},[69,764,94],{"class":93},[69,766,652],{"class":97},[69,768,94],{"class":93},[69,770,343],{"class":75},[69,772,773],{"class":124}," new",[69,775,664],{"class":128},[69,777,327],{"class":193},[69,779,94],{"class":93},[69,781,652],{"class":97},[69,783,94],{"class":93},[69,785,786],{"class":193},"))",[69,788,177],{"class":75},[69,790,718],{"class":109},[69,792,793,795,797],{"class":71,"line":386},[69,794,213],{"class":75},[69,796,80],{"class":79},[69,798,103],{"class":75},[24,800,801],{},"对于更简洁的写法（Vue 3.3+），可以使用字面量语法：",[61,803,805],{"className":433,"code":804,"language":98,"meta":65,"style":65},"const emit = defineEmits\u003C{\n  change: [value: string];\n  update: [id: number, payload: Record\u003Cstring, any>];\n}>();\n",[28,806,807,819,841,879],{"__ignoreMap":65},[69,808,809,811,813,815,817],{"class":71,"line":72},[69,810,117],{"class":116},[69,812,543],{"class":120},[69,814,125],{"class":124},[69,816,548],{"class":128},[69,818,132],{"class":75},[69,820,821,824,826,829,832,834,836,839],{"class":71,"line":106},[69,822,823],{"class":138},"  change",[69,825,142],{"class":124},[69,827,828],{"class":193}," [",[69,830,831],{"class":267},"value",[69,833,142],{"class":75},[69,835,146],{"class":145},[69,837,838],{"class":193},"]",[69,840,149],{"class":75},[69,842,843,846,848,850,853,855,857,859,861,863,865,867,869,871,873,875,877],{"class":71,"line":113},[69,844,845],{"class":138},"  update",[69,847,142],{"class":124},[69,849,828],{"class":193},[69,851,852],{"class":267},"id",[69,854,142],{"class":75},[69,856,160],{"class":145},[69,858,343],{"class":75},[69,860,615],{"class":267},[69,862,142],{"class":75},[69,864,620],{"class":267},[69,866,76],{"class":75},[69,868,625],{"class":145},[69,870,343],{"class":75},[69,872,630],{"class":145},[69,874,338],{"class":75},[69,876,838],{"class":193},[69,878,149],{"class":75},[69,880,881,883,885],{"class":71,"line":135},[69,882,202],{"class":75},[69,884,205],{"class":193},[69,886,149],{"class":75},[46,888,890],{"id":889},"_3-模板-ref-的类型标注","3. 模板 ref 的类型标注",[24,892,893,894,897],{},"当通过 ",[28,895,896],{},"ref"," 获取子组件实例或 DOM 元素时，需要标注正确的类型。",[57,899,901],{"id":900},"dom-元素","DOM 元素",[61,903,905],{"className":63,"code":904,"language":12,"meta":65,"style":65},"\u003Cscript setup lang=\"ts\">\nimport { ref, onMounted } from \"vue\";\nconst inputRef = ref\u003CHTMLInputElement | null>(null);\nonMounted(() => {\n  inputRef.value?.focus(); \u002F\u002F 使用可选链\n});\n\u003C\u002Fscript>\n\u003Ctemplate>\n  \u003Cinput ref=\"inputRef\" \u002F>\n\u003C\u002Ftemplate>\n",[28,906,907,927,955,989,1002,1025,1033,1041,1050,1072],{"__ignoreMap":65},[69,908,909,911,913,915,917,919,921,923,925],{"class":71,"line":72},[69,910,76],{"class":75},[69,912,80],{"class":79},[69,914,84],{"class":83},[69,916,87],{"class":83},[69,918,90],{"class":75},[69,920,94],{"class":93},[69,922,98],{"class":97},[69,924,94],{"class":93},[69,926,103],{"class":75},[69,928,929,932,934,937,939,942,944,947,949,951,953],{"class":71,"line":106},[69,930,931],{"class":260},"import",[69,933,740],{"class":75},[69,935,936],{"class":193}," ref",[69,938,343],{"class":75},[69,940,941],{"class":193}," onMounted",[69,943,750],{"class":75},[69,945,946],{"class":260}," from",[69,948,563],{"class":93},[69,950,12],{"class":97},[69,952,94],{"class":93},[69,954,149],{"class":75},[69,956,957,959,962,964,966,968,971,974,977,979,981,985,987],{"class":71,"line":113},[69,958,117],{"class":116},[69,960,961],{"class":120}," inputRef",[69,963,125],{"class":124},[69,965,936],{"class":128},[69,967,76],{"class":75},[69,969,970],{"class":267},"HTMLInputElement",[69,972,973],{"class":124}," |",[69,975,976],{"class":145}," null",[69,978,338],{"class":75},[69,980,327],{"class":193},[69,982,984],{"class":983},"s39Yj","null",[69,986,381],{"class":193},[69,988,149],{"class":75},[69,990,991,994,996,998,1000],{"class":71,"line":135},[69,992,993],{"class":128},"onMounted",[69,995,327],{"class":193},[69,997,205],{"class":75},[69,999,467],{"class":116},[69,1001,271],{"class":75},[69,1003,1004,1007,1010,1012,1015,1018,1020,1022],{"class":71,"line":152},[69,1005,1006],{"class":193},"  inputRef",[69,1008,1009],{"class":75},".",[69,1011,831],{"class":193},[69,1013,1014],{"class":75},"?.",[69,1016,1017],{"class":128},"focus",[69,1019,205],{"class":350},[69,1021,177],{"class":75},[69,1023,1024],{"class":109}," \u002F\u002F 使用可选链\n",[69,1026,1027,1029,1031],{"class":71,"line":165},[69,1028,378],{"class":75},[69,1030,381],{"class":193},[69,1032,149],{"class":75},[69,1034,1035,1037,1039],{"class":71,"line":183},[69,1036,213],{"class":75},[69,1038,80],{"class":79},[69,1040,103],{"class":75},[69,1042,1043,1045,1048],{"class":71,"line":199},[69,1044,76],{"class":75},[69,1046,1047],{"class":79},"template",[69,1049,103],{"class":75},[69,1051,1052,1055,1058,1060,1062,1064,1067,1069],{"class":71,"line":210},[69,1053,1054],{"class":75},"  \u003C",[69,1056,1057],{"class":79},"input",[69,1059,936],{"class":83},[69,1061,90],{"class":75},[69,1063,94],{"class":93},[69,1065,1066],{"class":97},"inputRef",[69,1068,94],{"class":93},[69,1070,1071],{"class":75}," \u002F>\n",[69,1073,1074,1076,1078],{"class":71,"line":362},[69,1075,213],{"class":75},[69,1077,1047],{"class":79},[69,1079,103],{"class":75},[57,1081,1082],{"id":1082},"子组件实例",[61,1084,1086],{"className":63,"code":1085,"language":12,"meta":65,"style":65},"\u003C!-- Child.vue -->\n\u003Cscript setup lang=\"ts\">\ndefineExpose({\n  reset: () => {\n    \u002F* ... *\u002F\n  },\n});\n\u003C\u002Fscript>\n\n\u003C!-- Parent.vue -->\n\u003Cscript setup lang=\"ts\">\nimport Child from \".\u002FChild.vue\";\nconst childRef = ref\u003CInstanceType\u003Ctypeof Child> | null>(null);\nfunction handleReset() {\n  childRef.value?.reset();\n}\n\u003C\u002Fscript>\n\u003Ctemplate>\n  \u003CChild ref=\"childRef\" \u002F>\n\u003C\u002Ftemplate>\n",[28,1087,1088,1093,1113,1123,1137,1142,1147,1155,1163,1167,1172,1192,1211,1252,1265,1284,1289,1298,1307,1328],{"__ignoreMap":65},[69,1089,1090],{"class":71,"line":72},[69,1091,1092],{"class":109},"\u003C!-- Child.vue -->\n",[69,1094,1095,1097,1099,1101,1103,1105,1107,1109,1111],{"class":71,"line":106},[69,1096,76],{"class":75},[69,1098,80],{"class":79},[69,1100,84],{"class":83},[69,1102,87],{"class":83},[69,1104,90],{"class":75},[69,1106,94],{"class":93},[69,1108,98],{"class":97},[69,1110,94],{"class":93},[69,1112,103],{"class":75},[69,1114,1115,1118,1120],{"class":71,"line":113},[69,1116,1117],{"class":128},"defineExpose",[69,1119,327],{"class":193},[69,1121,1122],{"class":75},"{\n",[69,1124,1125,1128,1130,1133,1135],{"class":71,"line":135},[69,1126,1127],{"class":128},"  reset",[69,1129,142],{"class":75},[69,1131,1132],{"class":75}," ()",[69,1134,467],{"class":116},[69,1136,271],{"class":75},[69,1138,1139],{"class":71,"line":152},[69,1140,1141],{"class":109},"    \u002F* ... *\u002F\n",[69,1143,1144],{"class":71,"line":165},[69,1145,1146],{"class":75},"  },\n",[69,1148,1149,1151,1153],{"class":71,"line":183},[69,1150,378],{"class":75},[69,1152,381],{"class":193},[69,1154,149],{"class":75},[69,1156,1157,1159,1161],{"class":71,"line":199},[69,1158,213],{"class":75},[69,1160,80],{"class":79},[69,1162,103],{"class":75},[69,1164,1165],{"class":71,"line":210},[69,1166,313],{"emptyLinePlaceholder":312},[69,1168,1169],{"class":71,"line":362},[69,1170,1171],{"class":109},"\u003C!-- Parent.vue -->\n",[69,1173,1174,1176,1178,1180,1182,1184,1186,1188,1190],{"class":71,"line":375},[69,1175,76],{"class":75},[69,1177,80],{"class":79},[69,1179,84],{"class":83},[69,1181,87],{"class":83},[69,1183,90],{"class":75},[69,1185,94],{"class":93},[69,1187,98],{"class":97},[69,1189,94],{"class":93},[69,1191,103],{"class":75},[69,1193,1194,1196,1199,1202,1204,1207,1209],{"class":71,"line":386},[69,1195,931],{"class":260},[69,1197,1198],{"class":193}," Child ",[69,1200,1201],{"class":260},"from",[69,1203,563],{"class":93},[69,1205,1206],{"class":97},".\u002FChild.vue",[69,1208,94],{"class":93},[69,1210,149],{"class":75},[69,1212,1214,1216,1219,1221,1223,1225,1228,1230,1233,1236,1238,1240,1242,1244,1246,1248,1250],{"class":71,"line":1213},13,[69,1215,117],{"class":116},[69,1217,1218],{"class":120}," childRef",[69,1220,125],{"class":124},[69,1222,936],{"class":128},[69,1224,76],{"class":75},[69,1226,1227],{"class":267},"InstanceType",[69,1229,76],{"class":75},[69,1231,1232],{"class":124},"typeof",[69,1234,1235],{"class":193}," Child",[69,1237,338],{"class":75},[69,1239,973],{"class":124},[69,1241,976],{"class":145},[69,1243,338],{"class":75},[69,1245,327],{"class":193},[69,1247,984],{"class":983},[69,1249,381],{"class":193},[69,1251,149],{"class":75},[69,1253,1255,1258,1261,1263],{"class":71,"line":1254},14,[69,1256,1257],{"class":116},"function",[69,1259,1260],{"class":128}," handleReset",[69,1262,205],{"class":75},[69,1264,271],{"class":75},[69,1266,1268,1271,1273,1275,1277,1280,1282],{"class":71,"line":1267},15,[69,1269,1270],{"class":193},"  childRef",[69,1272,1009],{"class":75},[69,1274,831],{"class":193},[69,1276,1014],{"class":75},[69,1278,1279],{"class":128},"reset",[69,1281,205],{"class":350},[69,1283,149],{"class":75},[69,1285,1287],{"class":71,"line":1286},16,[69,1288,307],{"class":75},[69,1290,1292,1294,1296],{"class":71,"line":1291},17,[69,1293,213],{"class":75},[69,1295,80],{"class":79},[69,1297,103],{"class":75},[69,1299,1301,1303,1305],{"class":71,"line":1300},18,[69,1302,76],{"class":75},[69,1304,1047],{"class":79},[69,1306,103],{"class":75},[69,1308,1310,1312,1315,1317,1319,1321,1324,1326],{"class":71,"line":1309},19,[69,1311,1054],{"class":75},[69,1313,1314],{"class":79},"Child",[69,1316,936],{"class":83},[69,1318,90],{"class":75},[69,1320,94],{"class":93},[69,1322,1323],{"class":97},"childRef",[69,1325,94],{"class":93},[69,1327,1071],{"class":75},[69,1329,1331,1333,1335],{"class":71,"line":1330},20,[69,1332,213],{"class":75},[69,1334,1047],{"class":79},[69,1336,103],{"class":75},[46,1338,1340,1341],{"id":1339},"_4-依赖注入的类型安全injectionkeyt","4. 依赖注入的类型安全：",[28,1342,1343],{},"InjectionKey\u003CT>",[24,1345,507,1346,1349,1350,1353,1354,37],{},[28,1347,1348],{},"InjectionKey"," 声明注入值的类型，避免 ",[28,1351,1352],{},"inject"," 返回 ",[28,1355,1356],{},"unknown",[61,1358,1360],{"className":433,"code":1359,"language":98,"meta":65,"style":65},"\u002F\u002F types.ts\nimport { InjectionKey, Ref } from \"vue\";\n\nexport interface User {\n  name: string;\n  age: number;\n}\n\nexport const userKey: InjectionKey\u003CRef\u003CUser>> = Symbol(\"user\");\nexport const updateUserKey: InjectionKey\u003C(user: User) => void> = Symbol(\"updateUser\");\n",[28,1361,1362,1367,1393,1397,1408,1419,1430,1434,1438,1483],{"__ignoreMap":65},[69,1363,1364],{"class":71,"line":72},[69,1365,1366],{"class":109},"\u002F\u002F types.ts\n",[69,1368,1369,1371,1373,1376,1378,1381,1383,1385,1387,1389,1391],{"class":71,"line":106},[69,1370,931],{"class":260},[69,1372,740],{"class":75},[69,1374,1375],{"class":193}," InjectionKey",[69,1377,343],{"class":75},[69,1379,1380],{"class":193}," Ref",[69,1382,750],{"class":75},[69,1384,946],{"class":260},[69,1386,563],{"class":93},[69,1388,12],{"class":97},[69,1390,94],{"class":93},[69,1392,149],{"class":75},[69,1394,1395],{"class":71,"line":113},[69,1396,313],{"emptyLinePlaceholder":312},[69,1398,1399,1401,1403,1406],{"class":71,"line":135},[69,1400,261],{"class":260},[69,1402,264],{"class":116},[69,1404,1405],{"class":267}," User",[69,1407,271],{"class":75},[69,1409,1410,1413,1415,1417],{"class":71,"line":152},[69,1411,1412],{"class":138},"  name",[69,1414,142],{"class":124},[69,1416,146],{"class":145},[69,1418,149],{"class":75},[69,1420,1421,1424,1426,1428],{"class":71,"line":165},[69,1422,1423],{"class":138},"  age",[69,1425,142],{"class":124},[69,1427,160],{"class":145},[69,1429,149],{"class":75},[69,1431,1432],{"class":71,"line":183},[69,1433,307],{"class":75},[69,1435,1436],{"class":71,"line":199},[69,1437,313],{"emptyLinePlaceholder":312},[69,1439,1440,1442,1445,1448,1450,1452,1454,1457,1459,1462,1465,1467,1470,1472,1474,1477,1479,1481],{"class":71,"line":210},[69,1441,261],{"class":260},[69,1443,1444],{"class":116}," const",[69,1446,1447],{"class":120}," userKey",[69,1449,142],{"class":124},[69,1451,1375],{"class":267},[69,1453,76],{"class":75},[69,1455,1456],{"class":267},"Ref",[69,1458,76],{"class":75},[69,1460,1461],{"class":267},"User",[69,1463,1464],{"class":75},">>",[69,1466,125],{"class":124},[69,1468,1469],{"class":128}," Symbol",[69,1471,327],{"class":193},[69,1473,94],{"class":93},[69,1475,1476],{"class":97},"user",[69,1478,94],{"class":93},[69,1480,381],{"class":193},[69,1482,149],{"class":75},[69,1484,1485,1487,1489,1492,1494,1496,1499,1501,1503,1505,1507,1509,1511,1513,1515,1517,1519,1521,1524,1526,1528],{"class":71,"line":362},[69,1486,261],{"class":260},[69,1488,1444],{"class":116},[69,1490,1491],{"class":120}," updateUserKey",[69,1493,142],{"class":124},[69,1495,1375],{"class":267},[69,1497,1498],{"class":75},"\u003C(",[69,1500,1476],{"class":456},[69,1502,142],{"class":124},[69,1504,1405],{"class":267},[69,1506,381],{"class":75},[69,1508,467],{"class":116},[69,1510,584],{"class":145},[69,1512,338],{"class":75},[69,1514,125],{"class":124},[69,1516,1469],{"class":128},[69,1518,327],{"class":193},[69,1520,94],{"class":93},[69,1522,1523],{"class":97},"updateUser",[69,1525,94],{"class":93},[69,1527,381],{"class":193},[69,1529,149],{"class":75},[61,1531,1533],{"className":63,"code":1532,"language":12,"meta":65,"style":65},"\u003C!-- Provider.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { provide, ref } from \"vue\";\nimport { userKey, updateUserKey } from \".\u002Ftypes\";\n\nconst user = ref({ name: \"Alice\", age: 25 });\nconst updateUser = (newUser: User) => {\n  user.value = newUser;\n};\nprovide(userKey, user);\nprovide(updateUserKey, updateUser);\n\u003C\u002Fscript>\n",[28,1534,1535,1540,1560,1585,1610,1614,1658,1683,1699,1704,1719,1733],{"__ignoreMap":65},[69,1536,1537],{"class":71,"line":72},[69,1538,1539],{"class":109},"\u003C!-- Provider.vue -->\n",[69,1541,1542,1544,1546,1548,1550,1552,1554,1556,1558],{"class":71,"line":106},[69,1543,76],{"class":75},[69,1545,80],{"class":79},[69,1547,84],{"class":83},[69,1549,87],{"class":83},[69,1551,90],{"class":75},[69,1553,94],{"class":93},[69,1555,98],{"class":97},[69,1557,94],{"class":93},[69,1559,103],{"class":75},[69,1561,1562,1564,1566,1569,1571,1573,1575,1577,1579,1581,1583],{"class":71,"line":113},[69,1563,931],{"class":260},[69,1565,740],{"class":75},[69,1567,1568],{"class":193}," provide",[69,1570,343],{"class":75},[69,1572,936],{"class":193},[69,1574,750],{"class":75},[69,1576,946],{"class":260},[69,1578,563],{"class":93},[69,1580,12],{"class":97},[69,1582,94],{"class":93},[69,1584,149],{"class":75},[69,1586,1587,1589,1591,1593,1595,1597,1599,1601,1603,1606,1608],{"class":71,"line":135},[69,1588,931],{"class":260},[69,1590,740],{"class":75},[69,1592,1447],{"class":193},[69,1594,343],{"class":75},[69,1596,1491],{"class":193},[69,1598,750],{"class":75},[69,1600,946],{"class":260},[69,1602,563],{"class":93},[69,1604,1605],{"class":97},".\u002Ftypes",[69,1607,94],{"class":93},[69,1609,149],{"class":75},[69,1611,1612],{"class":71,"line":152},[69,1613,313],{"emptyLinePlaceholder":312},[69,1615,1616,1618,1621,1623,1625,1627,1630,1633,1635,1637,1640,1642,1644,1647,1649,1652,1654,1656],{"class":71,"line":165},[69,1617,117],{"class":116},[69,1619,1620],{"class":120}," user",[69,1622,125],{"class":124},[69,1624,936],{"class":128},[69,1626,327],{"class":193},[69,1628,1629],{"class":75},"{",[69,1631,1632],{"class":350}," name",[69,1634,142],{"class":75},[69,1636,563],{"class":93},[69,1638,1639],{"class":97},"Alice",[69,1641,94],{"class":93},[69,1643,343],{"class":75},[69,1645,1646],{"class":350}," age",[69,1648,142],{"class":75},[69,1650,1651],{"class":355}," 25",[69,1653,750],{"class":75},[69,1655,381],{"class":193},[69,1657,149],{"class":75},[69,1659,1660,1662,1666,1668,1670,1673,1675,1677,1679,1681],{"class":71,"line":183},[69,1661,117],{"class":116},[69,1663,1665],{"class":1664},"sfCm-"," updateUser",[69,1667,125],{"class":124},[69,1669,453],{"class":75},[69,1671,1672],{"class":456},"newUser",[69,1674,142],{"class":124},[69,1676,1405],{"class":267},[69,1678,381],{"class":75},[69,1680,467],{"class":116},[69,1682,271],{"class":75},[69,1684,1685,1688,1690,1692,1694,1697],{"class":71,"line":199},[69,1686,1687],{"class":193},"  user",[69,1689,1009],{"class":75},[69,1691,831],{"class":193},[69,1693,125],{"class":124},[69,1695,1696],{"class":193}," newUser",[69,1698,149],{"class":75},[69,1700,1701],{"class":71,"line":210},[69,1702,1703],{"class":75},"};\n",[69,1705,1706,1709,1712,1714,1717],{"class":71,"line":362},[69,1707,1708],{"class":128},"provide",[69,1710,1711],{"class":193},"(userKey",[69,1713,343],{"class":75},[69,1715,1716],{"class":193}," user)",[69,1718,149],{"class":75},[69,1720,1721,1723,1726,1728,1731],{"class":71,"line":375},[69,1722,1708],{"class":128},[69,1724,1725],{"class":193},"(updateUserKey",[69,1727,343],{"class":75},[69,1729,1730],{"class":193}," updateUser)",[69,1732,149],{"class":75},[69,1734,1735,1737,1739],{"class":71,"line":386},[69,1736,213],{"class":75},[69,1738,80],{"class":79},[69,1740,103],{"class":75},[61,1742,1744],{"className":63,"code":1743,"language":12,"meta":65,"style":65},"\u003C!-- Consumer.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { inject } from \"vue\";\nimport { userKey, updateUserKey } from \".\u002Ftypes\";\n\nconst user = inject(userKey); \u002F\u002F 类型为 Ref\u003CUser> | undefined\nconst updateUser = inject(updateUserKey); \u002F\u002F (user: User) => void | undefined\n\nif (user && updateUser) {\n  console.log(user.value.name);\n  updateUser({ name: \"Bob\", age: 30 });\n}\n\u003C\u002Fscript>\n",[28,1745,1746,1751,1771,1792,1816,1820,1838,1856,1860,1876,1903,1938,1942],{"__ignoreMap":65},[69,1747,1748],{"class":71,"line":72},[69,1749,1750],{"class":109},"\u003C!-- Consumer.vue -->\n",[69,1752,1753,1755,1757,1759,1761,1763,1765,1767,1769],{"class":71,"line":106},[69,1754,76],{"class":75},[69,1756,80],{"class":79},[69,1758,84],{"class":83},[69,1760,87],{"class":83},[69,1762,90],{"class":75},[69,1764,94],{"class":93},[69,1766,98],{"class":97},[69,1768,94],{"class":93},[69,1770,103],{"class":75},[69,1772,1773,1775,1777,1780,1782,1784,1786,1788,1790],{"class":71,"line":113},[69,1774,931],{"class":260},[69,1776,740],{"class":75},[69,1778,1779],{"class":193}," inject",[69,1781,750],{"class":75},[69,1783,946],{"class":260},[69,1785,563],{"class":93},[69,1787,12],{"class":97},[69,1789,94],{"class":93},[69,1791,149],{"class":75},[69,1793,1794,1796,1798,1800,1802,1804,1806,1808,1810,1812,1814],{"class":71,"line":135},[69,1795,931],{"class":260},[69,1797,740],{"class":75},[69,1799,1447],{"class":193},[69,1801,343],{"class":75},[69,1803,1491],{"class":193},[69,1805,750],{"class":75},[69,1807,946],{"class":260},[69,1809,563],{"class":93},[69,1811,1605],{"class":97},[69,1813,94],{"class":93},[69,1815,149],{"class":75},[69,1817,1818],{"class":71,"line":152},[69,1819,313],{"emptyLinePlaceholder":312},[69,1821,1822,1824,1826,1828,1830,1833,1835],{"class":71,"line":165},[69,1823,117],{"class":116},[69,1825,1620],{"class":120},[69,1827,125],{"class":124},[69,1829,1779],{"class":128},[69,1831,1832],{"class":193},"(userKey)",[69,1834,177],{"class":75},[69,1836,1837],{"class":109}," \u002F\u002F 类型为 Ref\u003CUser> | undefined\n",[69,1839,1840,1842,1844,1846,1848,1851,1853],{"class":71,"line":183},[69,1841,117],{"class":116},[69,1843,1665],{"class":120},[69,1845,125],{"class":124},[69,1847,1779],{"class":128},[69,1849,1850],{"class":193},"(updateUserKey)",[69,1852,177],{"class":75},[69,1854,1855],{"class":109}," \u002F\u002F (user: User) => void | undefined\n",[69,1857,1858],{"class":71,"line":199},[69,1859,313],{"emptyLinePlaceholder":312},[69,1861,1862,1865,1868,1871,1874],{"class":71,"line":210},[69,1863,1864],{"class":260},"if",[69,1866,1867],{"class":193}," (user ",[69,1869,1870],{"class":124},"&&",[69,1872,1873],{"class":193}," updateUser) ",[69,1875,1122],{"class":75},[69,1877,1878,1881,1883,1886,1888,1890,1892,1894,1896,1899,1901],{"class":71,"line":362},[69,1879,1880],{"class":193},"  console",[69,1882,1009],{"class":75},[69,1884,1885],{"class":128},"log",[69,1887,327],{"class":350},[69,1889,1476],{"class":193},[69,1891,1009],{"class":75},[69,1893,831],{"class":193},[69,1895,1009],{"class":75},[69,1897,1898],{"class":193},"name",[69,1900,381],{"class":350},[69,1902,149],{"class":75},[69,1904,1905,1908,1910,1912,1914,1916,1918,1921,1923,1925,1927,1929,1932,1934,1936],{"class":71,"line":375},[69,1906,1907],{"class":128},"  updateUser",[69,1909,327],{"class":350},[69,1911,1629],{"class":75},[69,1913,1632],{"class":350},[69,1915,142],{"class":75},[69,1917,563],{"class":93},[69,1919,1920],{"class":97},"Bob",[69,1922,94],{"class":93},[69,1924,343],{"class":75},[69,1926,1646],{"class":350},[69,1928,142],{"class":75},[69,1930,1931],{"class":355}," 30",[69,1933,750],{"class":75},[69,1935,381],{"class":350},[69,1937,149],{"class":75},[69,1939,1940],{"class":71,"line":386},[69,1941,307],{"class":75},[69,1943,1944,1946,1948],{"class":71,"line":1213},[69,1945,213],{"class":75},[69,1947,80],{"class":79},[69,1949,103],{"class":75},[46,1951,1953,1954],{"id":1952},"_5-全局类型扩展componentcustomproperties","5. 全局类型扩展：",[28,1955,1956],{},"ComponentCustomProperties",[24,1958,1959,1960,1963],{},"当通过插件挂载全局属性（如 ",[28,1961,1962],{},"$axios","）或修改全局组件选项时，需要扩展 Vue 的类型接口。",[61,1965,1967],{"className":433,"code":1966,"language":98,"meta":65,"style":65},"\u002F\u002F main.ts\nimport axios from \"axios\";\nconst app = createApp(App);\napp.config.globalProperties.$axios = axios;\n",[28,1968,1969,1974,1992,2009],{"__ignoreMap":65},[69,1970,1971],{"class":71,"line":72},[69,1972,1973],{"class":109},"\u002F\u002F main.ts\n",[69,1975,1976,1978,1981,1983,1985,1988,1990],{"class":71,"line":106},[69,1977,931],{"class":260},[69,1979,1980],{"class":193}," axios ",[69,1982,1201],{"class":260},[69,1984,563],{"class":93},[69,1986,1987],{"class":97},"axios",[69,1989,94],{"class":93},[69,1991,149],{"class":75},[69,1993,1994,1996,1999,2001,2004,2007],{"class":71,"line":113},[69,1995,117],{"class":116},[69,1997,1998],{"class":120}," app",[69,2000,125],{"class":124},[69,2002,2003],{"class":128}," createApp",[69,2005,2006],{"class":193},"(App)",[69,2008,149],{"class":75},[69,2010,2011,2014,2016,2019,2021,2024,2026,2029,2031,2034],{"class":71,"line":135},[69,2012,2013],{"class":193},"app",[69,2015,1009],{"class":75},[69,2017,2018],{"class":193},"config",[69,2020,1009],{"class":75},[69,2022,2023],{"class":193},"globalProperties",[69,2025,1009],{"class":75},[69,2027,2028],{"class":193},"$axios ",[69,2030,90],{"class":124},[69,2032,2033],{"class":193}," axios",[69,2035,149],{"class":75},[61,2037,2039],{"className":433,"code":2038,"language":98,"meta":65,"style":65},"\u002F\u002F shims-vue.d.ts 或 global.d.ts\nimport axios from \"axios\";\n\ndeclare module \"vue\" {\n  interface ComponentCustomProperties {\n    $axios: typeof axios;\n    $translate: (key: string) => string;\n  }\n}\n",[28,2040,2041,2046,2062,2066,2082,2092,2106,2130,2135],{"__ignoreMap":65},[69,2042,2043],{"class":71,"line":72},[69,2044,2045],{"class":109},"\u002F\u002F shims-vue.d.ts 或 global.d.ts\n",[69,2047,2048,2050,2052,2054,2056,2058,2060],{"class":71,"line":106},[69,2049,931],{"class":260},[69,2051,1980],{"class":193},[69,2053,1201],{"class":260},[69,2055,563],{"class":93},[69,2057,1987],{"class":97},[69,2059,94],{"class":93},[69,2061,149],{"class":75},[69,2063,2064],{"class":71,"line":113},[69,2065,313],{"emptyLinePlaceholder":312},[69,2067,2068,2071,2074,2076,2078,2080],{"class":71,"line":135},[69,2069,2070],{"class":116},"declare",[69,2072,2073],{"class":116}," module",[69,2075,563],{"class":93},[69,2077,12],{"class":97},[69,2079,94],{"class":93},[69,2081,271],{"class":75},[69,2083,2084,2087,2090],{"class":71,"line":152},[69,2085,2086],{"class":116},"  interface",[69,2088,2089],{"class":267}," ComponentCustomProperties",[69,2091,271],{"class":75},[69,2093,2094,2097,2099,2102,2104],{"class":71,"line":165},[69,2095,2096],{"class":138},"    $axios",[69,2098,142],{"class":124},[69,2100,2101],{"class":124}," typeof",[69,2103,2033],{"class":193},[69,2105,149],{"class":75},[69,2107,2108,2111,2113,2115,2118,2120,2122,2124,2126,2128],{"class":71,"line":183},[69,2109,2110],{"class":447},"    $translate",[69,2112,142],{"class":124},[69,2114,453],{"class":75},[69,2116,2117],{"class":456},"key",[69,2119,142],{"class":124},[69,2121,146],{"class":145},[69,2123,381],{"class":75},[69,2125,467],{"class":116},[69,2127,146],{"class":145},[69,2129,149],{"class":75},[69,2131,2132],{"class":71,"line":199},[69,2133,2134],{"class":75},"  }\n",[69,2136,2137],{"class":71,"line":210},[69,2138,307],{"class":75},[24,2140,2141,2142,2145,2146,2149],{},"之后在组合式 API 中可以通过 ",[28,2143,2144],{},"getCurrentInstance()"," 访问，但推荐使用依赖注入或 composable 封装。在模板中可以直接使用 ",[28,2147,2148],{},"{{ $axios }}","（不推荐）。",[46,2151,2153],{"id":2152},"_6-pinia-store-的-typescript-最佳实践","6. Pinia store 的 TypeScript 最佳实践",[24,2155,2156,2157,2160],{},"Pinia 对 TypeScript 支持极佳，尤其是 ",[403,2158,2159],{},"Setup store","（推荐）会自动推导类型。",[57,2162,2164],{"id":2163},"setup-store自动类型推导","Setup Store（自动类型推导）",[61,2166,2168],{"className":433,"code":2167,"language":98,"meta":65,"style":65},"\u002F\u002F stores\u002Fuser.ts\nimport { defineStore } from \"pinia\";\nimport { ref, computed } from \"vue\";\n\nexport const useUserStore = defineStore(\"user\", () => {\n  const name = ref(\"Alice\");\n  const age = ref(25);\n  const isAdult = computed(() => age.value >= 18);\n  function setAge(newAge: number) {\n    age.value = newAge;\n  }\n  return { name, age, isAdult, setAge };\n});\n",[28,2169,2170,2175,2197,2222,2226,2255,2278,2297,2330,2351,2367,2371,2395],{"__ignoreMap":65},[69,2171,2172],{"class":71,"line":72},[69,2173,2174],{"class":109},"\u002F\u002F stores\u002Fuser.ts\n",[69,2176,2177,2179,2181,2184,2186,2188,2190,2193,2195],{"class":71,"line":106},[69,2178,931],{"class":260},[69,2180,740],{"class":75},[69,2182,2183],{"class":193}," defineStore",[69,2185,750],{"class":75},[69,2187,946],{"class":260},[69,2189,563],{"class":93},[69,2191,2192],{"class":97},"pinia",[69,2194,94],{"class":93},[69,2196,149],{"class":75},[69,2198,2199,2201,2203,2205,2207,2210,2212,2214,2216,2218,2220],{"class":71,"line":113},[69,2200,931],{"class":260},[69,2202,740],{"class":75},[69,2204,936],{"class":193},[69,2206,343],{"class":75},[69,2208,2209],{"class":193}," computed",[69,2211,750],{"class":75},[69,2213,946],{"class":260},[69,2215,563],{"class":93},[69,2217,12],{"class":97},[69,2219,94],{"class":93},[69,2221,149],{"class":75},[69,2223,2224],{"class":71,"line":135},[69,2225,313],{"emptyLinePlaceholder":312},[69,2227,2228,2230,2232,2235,2237,2239,2241,2243,2245,2247,2249,2251,2253],{"class":71,"line":152},[69,2229,261],{"class":260},[69,2231,1444],{"class":116},[69,2233,2234],{"class":120}," useUserStore",[69,2236,125],{"class":124},[69,2238,2183],{"class":128},[69,2240,327],{"class":193},[69,2242,94],{"class":93},[69,2244,1476],{"class":97},[69,2246,94],{"class":93},[69,2248,343],{"class":75},[69,2250,1132],{"class":75},[69,2252,467],{"class":116},[69,2254,271],{"class":75},[69,2256,2257,2260,2262,2264,2266,2268,2270,2272,2274,2276],{"class":71,"line":165},[69,2258,2259],{"class":116},"  const",[69,2261,1632],{"class":120},[69,2263,125],{"class":124},[69,2265,936],{"class":128},[69,2267,327],{"class":350},[69,2269,94],{"class":93},[69,2271,1639],{"class":97},[69,2273,94],{"class":93},[69,2275,381],{"class":350},[69,2277,149],{"class":75},[69,2279,2280,2282,2284,2286,2288,2290,2293,2295],{"class":71,"line":183},[69,2281,2259],{"class":116},[69,2283,1646],{"class":120},[69,2285,125],{"class":124},[69,2287,936],{"class":128},[69,2289,327],{"class":350},[69,2291,2292],{"class":355},"25",[69,2294,381],{"class":350},[69,2296,149],{"class":75},[69,2298,2299,2301,2304,2306,2308,2310,2312,2314,2316,2318,2320,2323,2326,2328],{"class":71,"line":199},[69,2300,2259],{"class":116},[69,2302,2303],{"class":120}," isAdult",[69,2305,125],{"class":124},[69,2307,2209],{"class":128},[69,2309,327],{"class":350},[69,2311,205],{"class":75},[69,2313,467],{"class":116},[69,2315,1646],{"class":193},[69,2317,1009],{"class":75},[69,2319,831],{"class":193},[69,2321,2322],{"class":124}," >=",[69,2324,2325],{"class":355}," 18",[69,2327,381],{"class":350},[69,2329,149],{"class":75},[69,2331,2332,2335,2338,2340,2343,2345,2347,2349],{"class":71,"line":210},[69,2333,2334],{"class":116},"  function",[69,2336,2337],{"class":128}," setAge",[69,2339,327],{"class":75},[69,2341,2342],{"class":456},"newAge",[69,2344,142],{"class":124},[69,2346,160],{"class":145},[69,2348,381],{"class":75},[69,2350,271],{"class":75},[69,2352,2353,2356,2358,2360,2362,2365],{"class":71,"line":362},[69,2354,2355],{"class":193},"    age",[69,2357,1009],{"class":75},[69,2359,831],{"class":193},[69,2361,125],{"class":124},[69,2363,2364],{"class":193}," newAge",[69,2366,149],{"class":75},[69,2368,2369],{"class":71,"line":375},[69,2370,2134],{"class":75},[69,2372,2373,2376,2378,2380,2382,2384,2386,2388,2390,2392],{"class":71,"line":386},[69,2374,2375],{"class":260},"  return",[69,2377,740],{"class":75},[69,2379,1632],{"class":193},[69,2381,343],{"class":75},[69,2383,1646],{"class":193},[69,2385,343],{"class":75},[69,2387,2303],{"class":193},[69,2389,343],{"class":75},[69,2391,2337],{"class":193},[69,2393,2394],{"class":75}," };\n",[69,2396,2397,2399,2401],{"class":71,"line":1213},[69,2398,378],{"class":75},[69,2400,381],{"class":193},[69,2402,149],{"class":75},[24,2404,2405],{},"在组件中使用时，所有属性和方法都有完整类型：",[61,2407,2409],{"className":63,"code":2408,"language":12,"meta":65,"style":65},"\u003Cscript setup lang=\"ts\">\nimport { useUserStore } from \"@\u002Fstores\u002Fuser\";\nconst userStore = useUserStore();\nuserStore.setAge(30); \u002F\u002F ✅ 参数类型为 number\nconsole.log(userStore.isAdult); \u002F\u002F boolean\n\u003C\u002Fscript>\n",[28,2410,2411,2431,2452,2467,2489,2511],{"__ignoreMap":65},[69,2412,2413,2415,2417,2419,2421,2423,2425,2427,2429],{"class":71,"line":72},[69,2414,76],{"class":75},[69,2416,80],{"class":79},[69,2418,84],{"class":83},[69,2420,87],{"class":83},[69,2422,90],{"class":75},[69,2424,94],{"class":93},[69,2426,98],{"class":97},[69,2428,94],{"class":93},[69,2430,103],{"class":75},[69,2432,2433,2435,2437,2439,2441,2443,2445,2448,2450],{"class":71,"line":106},[69,2434,931],{"class":260},[69,2436,740],{"class":75},[69,2438,2234],{"class":193},[69,2440,750],{"class":75},[69,2442,946],{"class":260},[69,2444,563],{"class":93},[69,2446,2447],{"class":97},"@\u002Fstores\u002Fuser",[69,2449,94],{"class":93},[69,2451,149],{"class":75},[69,2453,2454,2456,2459,2461,2463,2465],{"class":71,"line":113},[69,2455,117],{"class":116},[69,2457,2458],{"class":120}," userStore",[69,2460,125],{"class":124},[69,2462,2234],{"class":128},[69,2464,205],{"class":193},[69,2466,149],{"class":75},[69,2468,2469,2472,2474,2477,2479,2482,2484,2486],{"class":71,"line":135},[69,2470,2471],{"class":193},"userStore",[69,2473,1009],{"class":75},[69,2475,2476],{"class":128},"setAge",[69,2478,327],{"class":193},[69,2480,2481],{"class":355},"30",[69,2483,381],{"class":193},[69,2485,177],{"class":75},[69,2487,2488],{"class":109}," \u002F\u002F ✅ 参数类型为 number\n",[69,2490,2491,2494,2496,2498,2501,2503,2506,2508],{"class":71,"line":152},[69,2492,2493],{"class":193},"console",[69,2495,1009],{"class":75},[69,2497,1885],{"class":128},[69,2499,2500],{"class":193},"(userStore",[69,2502,1009],{"class":75},[69,2504,2505],{"class":193},"isAdult)",[69,2507,177],{"class":75},[69,2509,2510],{"class":109}," \u002F\u002F boolean\n",[69,2512,2513,2515,2517],{"class":71,"line":165},[69,2514,213],{"class":75},[69,2516,80],{"class":79},[69,2518,103],{"class":75},[57,2520,2522],{"id":2521},"options-store-类型标注","Options Store 类型标注",[24,2524,2525],{},"若使用 Options Store，需手动标注类型：",[61,2527,2529],{"className":433,"code":2528,"language":98,"meta":65,"style":65},"interface UserState {\n  name: string;\n  age: number;\n}\nexport const useUserStore = defineStore(\"user\", {\n  state: (): UserState => ({ name: \"Alice\", age: 25 }),\n  getters: {\n    isAdult: (state) => state.age >= 18,\n  },\n  actions: {\n    setAge(age: number) {\n      this.age = age;\n    },\n  },\n});\n",[28,2530,2531,2541,2551,2561,2565,2589,2632,2641,2672,2676,2685,2703,2718,2723,2727],{"__ignoreMap":65},[69,2532,2533,2536,2539],{"class":71,"line":72},[69,2534,2535],{"class":116},"interface",[69,2537,2538],{"class":267}," UserState",[69,2540,271],{"class":75},[69,2542,2543,2545,2547,2549],{"class":71,"line":106},[69,2544,1412],{"class":138},[69,2546,142],{"class":124},[69,2548,146],{"class":145},[69,2550,149],{"class":75},[69,2552,2553,2555,2557,2559],{"class":71,"line":113},[69,2554,1423],{"class":138},[69,2556,142],{"class":124},[69,2558,160],{"class":145},[69,2560,149],{"class":75},[69,2562,2563],{"class":71,"line":135},[69,2564,307],{"class":75},[69,2566,2567,2569,2571,2573,2575,2577,2579,2581,2583,2585,2587],{"class":71,"line":152},[69,2568,261],{"class":260},[69,2570,1444],{"class":116},[69,2572,2234],{"class":120},[69,2574,125],{"class":124},[69,2576,2183],{"class":128},[69,2578,327],{"class":193},[69,2580,94],{"class":93},[69,2582,1476],{"class":97},[69,2584,94],{"class":93},[69,2586,343],{"class":75},[69,2588,271],{"class":75},[69,2590,2591,2594,2596,2598,2600,2602,2604,2606,2608,2610,2612,2614,2616,2618,2620,2622,2624,2626,2628,2630],{"class":71,"line":165},[69,2592,2593],{"class":128},"  state",[69,2595,142],{"class":75},[69,2597,1132],{"class":75},[69,2599,142],{"class":124},[69,2601,2538],{"class":267},[69,2603,467],{"class":116},[69,2605,453],{"class":193},[69,2607,1629],{"class":75},[69,2609,1632],{"class":350},[69,2611,142],{"class":75},[69,2613,563],{"class":93},[69,2615,1639],{"class":97},[69,2617,94],{"class":93},[69,2619,343],{"class":75},[69,2621,1646],{"class":350},[69,2623,142],{"class":75},[69,2625,1651],{"class":355},[69,2627,750],{"class":75},[69,2629,381],{"class":193},[69,2631,359],{"class":75},[69,2633,2634,2637,2639],{"class":71,"line":183},[69,2635,2636],{"class":350},"  getters",[69,2638,142],{"class":75},[69,2640,271],{"class":75},[69,2642,2643,2646,2648,2650,2653,2655,2657,2660,2662,2665,2668,2670],{"class":71,"line":199},[69,2644,2645],{"class":128},"    isAdult",[69,2647,142],{"class":75},[69,2649,453],{"class":75},[69,2651,2652],{"class":456},"state",[69,2654,381],{"class":75},[69,2656,467],{"class":116},[69,2658,2659],{"class":193}," state",[69,2661,1009],{"class":75},[69,2663,2664],{"class":193},"age ",[69,2666,2667],{"class":124},">=",[69,2669,2325],{"class":355},[69,2671,359],{"class":75},[69,2673,2674],{"class":71,"line":210},[69,2675,1146],{"class":75},[69,2677,2678,2681,2683],{"class":71,"line":362},[69,2679,2680],{"class":350},"  actions",[69,2682,142],{"class":75},[69,2684,271],{"class":75},[69,2686,2687,2690,2692,2695,2697,2699,2701],{"class":71,"line":375},[69,2688,2689],{"class":447},"    setAge",[69,2691,327],{"class":75},[69,2693,2694],{"class":456},"age",[69,2696,142],{"class":124},[69,2698,160],{"class":145},[69,2700,381],{"class":75},[69,2702,271],{"class":75},[69,2704,2705,2708,2710,2712,2714,2716],{"class":71,"line":386},[69,2706,2707],{"class":983},"      this",[69,2709,1009],{"class":75},[69,2711,2694],{"class":193},[69,2713,125],{"class":124},[69,2715,1646],{"class":193},[69,2717,149],{"class":75},[69,2719,2720],{"class":71,"line":1213},[69,2721,2722],{"class":75},"    },\n",[69,2724,2725],{"class":71,"line":1254},[69,2726,1146],{"class":75},[69,2728,2729,2731,2733],{"class":71,"line":1267},[69,2730,378],{"class":75},[69,2732,381],{"class":193},[69,2734,149],{"class":75},[57,2736,2738],{"id":2737},"跨-store-类型引用","跨 store 类型引用",[61,2740,2742],{"className":433,"code":2741,"language":98,"meta":65,"style":65},"import { useCartStore } from \".\u002Fcart\";\nconst cart = useCartStore();\n\u002F\u002F cart 具有完整类型\n",[28,2743,2744,2766,2781],{"__ignoreMap":65},[69,2745,2746,2748,2750,2753,2755,2757,2759,2762,2764],{"class":71,"line":72},[69,2747,931],{"class":260},[69,2749,740],{"class":75},[69,2751,2752],{"class":193}," useCartStore",[69,2754,750],{"class":75},[69,2756,946],{"class":260},[69,2758,563],{"class":93},[69,2760,2761],{"class":97},".\u002Fcart",[69,2763,94],{"class":93},[69,2765,149],{"class":75},[69,2767,2768,2770,2773,2775,2777,2779],{"class":71,"line":106},[69,2769,117],{"class":116},[69,2771,2772],{"class":120}," cart",[69,2774,125],{"class":124},[69,2776,2752],{"class":128},[69,2778,205],{"class":193},[69,2780,149],{"class":75},[69,2782,2783],{"class":71,"line":113},[69,2784,2785],{"class":109},"\u002F\u002F cart 具有完整类型\n",[46,2787,2789],{"id":2788},"_7-组合式函数的类型设计","7. 组合式函数的类型设计",[24,2791,2792],{},"设计 Composable（组合式函数）时，应提供清晰的返回类型声明和泛型约束。",[57,2794,2795],{"id":2795},"显式返回类型声明",[61,2797,2799],{"className":433,"code":2798,"language":98,"meta":65,"style":65},"import { ref, Ref } from \"vue\";\n\ninterface UseCounterReturn {\n  count: Ref\u003Cnumber>;\n  increment: () => void;\n  reset: () => void;\n}\n\nexport function useCounter(initial: number = 0): UseCounterReturn {\n  const count = ref(initial);\n  const increment = () => count.value++;\n  const reset = () => {\n    count.value = initial;\n  };\n  return { count, increment, reset };\n}\n",[28,2800,2801,2825,2829,2838,2853,2868,2882,2886,2890,2921,2940,2964,2979,2995,3000,3018],{"__ignoreMap":65},[69,2802,2803,2805,2807,2809,2811,2813,2815,2817,2819,2821,2823],{"class":71,"line":72},[69,2804,931],{"class":260},[69,2806,740],{"class":75},[69,2808,936],{"class":193},[69,2810,343],{"class":75},[69,2812,1380],{"class":193},[69,2814,750],{"class":75},[69,2816,946],{"class":260},[69,2818,563],{"class":93},[69,2820,12],{"class":97},[69,2822,94],{"class":93},[69,2824,149],{"class":75},[69,2826,2827],{"class":71,"line":106},[69,2828,313],{"emptyLinePlaceholder":312},[69,2830,2831,2833,2836],{"class":71,"line":113},[69,2832,2535],{"class":116},[69,2834,2835],{"class":267}," UseCounterReturn",[69,2837,271],{"class":75},[69,2839,2840,2842,2844,2846,2848,2851],{"class":71,"line":135},[69,2841,155],{"class":138},[69,2843,142],{"class":124},[69,2845,1380],{"class":267},[69,2847,76],{"class":75},[69,2849,2850],{"class":145},"number",[69,2852,478],{"class":75},[69,2854,2855,2858,2860,2862,2864,2866],{"class":71,"line":152},[69,2856,2857],{"class":447},"  increment",[69,2859,142],{"class":124},[69,2861,1132],{"class":75},[69,2863,467],{"class":116},[69,2865,584],{"class":145},[69,2867,149],{"class":75},[69,2869,2870,2872,2874,2876,2878,2880],{"class":71,"line":165},[69,2871,1127],{"class":447},[69,2873,142],{"class":124},[69,2875,1132],{"class":75},[69,2877,467],{"class":116},[69,2879,584],{"class":145},[69,2881,149],{"class":75},[69,2883,2884],{"class":71,"line":183},[69,2885,307],{"class":75},[69,2887,2888],{"class":71,"line":199},[69,2889,313],{"emptyLinePlaceholder":312},[69,2891,2892,2894,2897,2900,2902,2905,2907,2909,2911,2913,2915,2917,2919],{"class":71,"line":210},[69,2893,261],{"class":260},[69,2895,2896],{"class":116}," function",[69,2898,2899],{"class":128}," useCounter",[69,2901,327],{"class":75},[69,2903,2904],{"class":456},"initial",[69,2906,142],{"class":124},[69,2908,160],{"class":145},[69,2910,125],{"class":124},[69,2912,356],{"class":355},[69,2914,381],{"class":75},[69,2916,142],{"class":124},[69,2918,2835],{"class":267},[69,2920,271],{"class":75},[69,2922,2923,2925,2928,2930,2932,2934,2936,2938],{"class":71,"line":362},[69,2924,2259],{"class":116},[69,2926,2927],{"class":120}," count",[69,2929,125],{"class":124},[69,2931,936],{"class":128},[69,2933,327],{"class":350},[69,2935,2904],{"class":193},[69,2937,381],{"class":350},[69,2939,149],{"class":75},[69,2941,2942,2944,2947,2949,2951,2953,2955,2957,2959,2962],{"class":71,"line":375},[69,2943,2259],{"class":116},[69,2945,2946],{"class":1664}," increment",[69,2948,125],{"class":124},[69,2950,1132],{"class":75},[69,2952,467],{"class":116},[69,2954,2927],{"class":193},[69,2956,1009],{"class":75},[69,2958,831],{"class":193},[69,2960,2961],{"class":124},"++",[69,2963,149],{"class":75},[69,2965,2966,2968,2971,2973,2975,2977],{"class":71,"line":386},[69,2967,2259],{"class":116},[69,2969,2970],{"class":1664}," reset",[69,2972,125],{"class":124},[69,2974,1132],{"class":75},[69,2976,467],{"class":116},[69,2978,271],{"class":75},[69,2980,2981,2984,2986,2988,2990,2993],{"class":71,"line":1213},[69,2982,2983],{"class":193},"    count",[69,2985,1009],{"class":75},[69,2987,831],{"class":193},[69,2989,125],{"class":124},[69,2991,2992],{"class":193}," initial",[69,2994,149],{"class":75},[69,2996,2997],{"class":71,"line":1254},[69,2998,2999],{"class":75},"  };\n",[69,3001,3002,3004,3006,3008,3010,3012,3014,3016],{"class":71,"line":1267},[69,3003,2375],{"class":260},[69,3005,740],{"class":75},[69,3007,2927],{"class":193},[69,3009,343],{"class":75},[69,3011,2946],{"class":193},[69,3013,343],{"class":75},[69,3015,2970],{"class":193},[69,3017,2394],{"class":75},[69,3019,3020],{"class":71,"line":1286},[69,3021,307],{"class":75},[57,3023,3024],{"id":3024},"泛型组合式函数",[61,3026,3028],{"className":433,"code":3027,"language":98,"meta":65,"style":65},"import { ref, Ref, unref, MaybeRef } from \"vue\";\n\n\u002F\u002F 约束 T 为某个类型，返回值使用泛型\nexport function useFetch\u003CT>(url: MaybeRef\u003Cstring>): {\n  data: Ref\u003CT | null>;\n  error: Ref\u003CError | null>;\n  loading: Ref\u003Cboolean>;\n} {\n  const data = ref\u003CT | null>(null);\n  const error = ref\u003CError | null>(null);\n  const loading = ref(false);\n  \u002F\u002F ... 实现\n  return { data, error, loading };\n}\n\n\u002F\u002F 使用时指定类型\nconst { data } = useFetch\u003CUser[]>(\"\u002Fapi\u002Fusers\");\n\u002F\u002F data 类型为 Ref\u003CUser[] | null>\n",[28,3029,3030,3064,3068,3073,3107,3126,3146,3162,3168,3197,3226,3246,3251,3269,3273,3277,3282,3317],{"__ignoreMap":65},[69,3031,3032,3034,3036,3038,3040,3042,3044,3047,3049,3052,3054,3056,3058,3060,3062],{"class":71,"line":72},[69,3033,931],{"class":260},[69,3035,740],{"class":75},[69,3037,936],{"class":193},[69,3039,343],{"class":75},[69,3041,1380],{"class":193},[69,3043,343],{"class":75},[69,3045,3046],{"class":193}," unref",[69,3048,343],{"class":75},[69,3050,3051],{"class":193}," MaybeRef",[69,3053,750],{"class":75},[69,3055,946],{"class":260},[69,3057,563],{"class":93},[69,3059,12],{"class":97},[69,3061,94],{"class":93},[69,3063,149],{"class":75},[69,3065,3066],{"class":71,"line":106},[69,3067,313],{"emptyLinePlaceholder":312},[69,3069,3070],{"class":71,"line":113},[69,3071,3072],{"class":109},"\u002F\u002F 约束 T 为某个类型，返回值使用泛型\n",[69,3074,3075,3077,3079,3082,3084,3087,3090,3093,3095,3097,3099,3101,3103,3105],{"class":71,"line":135},[69,3076,261],{"class":260},[69,3078,2896],{"class":116},[69,3080,3081],{"class":128}," useFetch",[69,3083,76],{"class":75},[69,3085,3086],{"class":267},"T",[69,3088,3089],{"class":75},">(",[69,3091,3092],{"class":456},"url",[69,3094,142],{"class":124},[69,3096,3051],{"class":267},[69,3098,76],{"class":75},[69,3100,625],{"class":145},[69,3102,633],{"class":75},[69,3104,142],{"class":124},[69,3106,271],{"class":75},[69,3108,3109,3112,3114,3116,3118,3120,3122,3124],{"class":71,"line":152},[69,3110,3111],{"class":138},"  data",[69,3113,142],{"class":124},[69,3115,1380],{"class":267},[69,3117,76],{"class":75},[69,3119,3086],{"class":267},[69,3121,973],{"class":124},[69,3123,976],{"class":145},[69,3125,478],{"class":75},[69,3127,3128,3131,3133,3135,3137,3140,3142,3144],{"class":71,"line":165},[69,3129,3130],{"class":138},"  error",[69,3132,142],{"class":124},[69,3134,1380],{"class":267},[69,3136,76],{"class":75},[69,3138,3139],{"class":267},"Error",[69,3141,973],{"class":124},[69,3143,976],{"class":145},[69,3145,478],{"class":75},[69,3147,3148,3151,3153,3155,3157,3160],{"class":71,"line":183},[69,3149,3150],{"class":138},"  loading",[69,3152,142],{"class":124},[69,3154,1380],{"class":267},[69,3156,76],{"class":75},[69,3158,3159],{"class":145},"boolean",[69,3161,478],{"class":75},[69,3163,3164,3166],{"class":71,"line":199},[69,3165,378],{"class":75},[69,3167,271],{"class":75},[69,3169,3170,3172,3175,3177,3179,3181,3183,3185,3187,3189,3191,3193,3195],{"class":71,"line":210},[69,3171,2259],{"class":116},[69,3173,3174],{"class":120}," data",[69,3176,125],{"class":124},[69,3178,936],{"class":128},[69,3180,76],{"class":75},[69,3182,3086],{"class":267},[69,3184,973],{"class":124},[69,3186,976],{"class":145},[69,3188,338],{"class":75},[69,3190,327],{"class":350},[69,3192,984],{"class":983},[69,3194,381],{"class":350},[69,3196,149],{"class":75},[69,3198,3199,3201,3204,3206,3208,3210,3212,3214,3216,3218,3220,3222,3224],{"class":71,"line":362},[69,3200,2259],{"class":116},[69,3202,3203],{"class":120}," error",[69,3205,125],{"class":124},[69,3207,936],{"class":128},[69,3209,76],{"class":75},[69,3211,3139],{"class":267},[69,3213,973],{"class":124},[69,3215,976],{"class":145},[69,3217,338],{"class":75},[69,3219,327],{"class":350},[69,3221,984],{"class":983},[69,3223,381],{"class":350},[69,3225,149],{"class":75},[69,3227,3228,3230,3233,3235,3237,3239,3242,3244],{"class":71,"line":375},[69,3229,2259],{"class":116},[69,3231,3232],{"class":120}," loading",[69,3234,125],{"class":124},[69,3236,936],{"class":128},[69,3238,327],{"class":350},[69,3240,3241],{"class":369},"false",[69,3243,381],{"class":350},[69,3245,149],{"class":75},[69,3247,3248],{"class":71,"line":386},[69,3249,3250],{"class":109},"  \u002F\u002F ... 实现\n",[69,3252,3253,3255,3257,3259,3261,3263,3265,3267],{"class":71,"line":1213},[69,3254,2375],{"class":260},[69,3256,740],{"class":75},[69,3258,3174],{"class":193},[69,3260,343],{"class":75},[69,3262,3203],{"class":193},[69,3264,343],{"class":75},[69,3266,3232],{"class":193},[69,3268,2394],{"class":75},[69,3270,3271],{"class":71,"line":1254},[69,3272,307],{"class":75},[69,3274,3275],{"class":71,"line":1267},[69,3276,313],{"emptyLinePlaceholder":312},[69,3278,3279],{"class":71,"line":1286},[69,3280,3281],{"class":109},"\u002F\u002F 使用时指定类型\n",[69,3283,3284,3286,3288,3290,3292,3294,3296,3298,3300,3302,3304,3306,3308,3311,3313,3315],{"class":71,"line":1291},[69,3285,117],{"class":116},[69,3287,740],{"class":75},[69,3289,3174],{"class":120},[69,3291,750],{"class":75},[69,3293,125],{"class":124},[69,3295,3081],{"class":128},[69,3297,76],{"class":75},[69,3299,1461],{"class":267},[69,3301,194],{"class":193},[69,3303,338],{"class":75},[69,3305,327],{"class":193},[69,3307,94],{"class":93},[69,3309,3310],{"class":97},"\u002Fapi\u002Fusers",[69,3312,94],{"class":93},[69,3314,381],{"class":193},[69,3316,149],{"class":75},[69,3318,3319],{"class":71,"line":1300},[69,3320,3321],{"class":109},"\u002F\u002F data 类型为 Ref\u003CUser[] | null>\n",[57,3323,3325,3326,3329],{"id":3324},"处理-mayberef-参数","处理 ",[28,3327,3328],{},"MaybeRef"," 参数",[24,3331,3332,3333,3336,3337,3339],{},"Vue 3.3+ 提供了 ",[28,3334,3335],{},"toValue"," 辅助函数，可统一处理 ",[28,3338,1456],{}," 或普通值：",[61,3341,3343],{"className":433,"code":3342,"language":98,"meta":65,"style":65},"import { toValue, type MaybeRefOrGetter } from \"vue\";\n\nexport function useDouble(value: MaybeRefOrGetter\u003Cnumber>) {\n  const double = computed(() => toValue(value) * 2);\n  return { double };\n}\n",[28,3344,3345,3374,3378,3403,3439,3449],{"__ignoreMap":65},[69,3346,3347,3349,3351,3354,3356,3359,3362,3364,3366,3368,3370,3372],{"class":71,"line":72},[69,3348,931],{"class":260},[69,3350,740],{"class":75},[69,3352,3353],{"class":193}," toValue",[69,3355,343],{"class":75},[69,3357,3358],{"class":260}," type",[69,3360,3361],{"class":193}," MaybeRefOrGetter",[69,3363,750],{"class":75},[69,3365,946],{"class":260},[69,3367,563],{"class":93},[69,3369,12],{"class":97},[69,3371,94],{"class":93},[69,3373,149],{"class":75},[69,3375,3376],{"class":71,"line":106},[69,3377,313],{"emptyLinePlaceholder":312},[69,3379,3380,3382,3384,3387,3389,3391,3393,3395,3397,3399,3401],{"class":71,"line":113},[69,3381,261],{"class":260},[69,3383,2896],{"class":116},[69,3385,3386],{"class":128}," useDouble",[69,3388,327],{"class":75},[69,3390,831],{"class":456},[69,3392,142],{"class":124},[69,3394,3361],{"class":267},[69,3396,76],{"class":75},[69,3398,2850],{"class":145},[69,3400,633],{"class":75},[69,3402,271],{"class":75},[69,3404,3405,3407,3410,3412,3414,3416,3418,3420,3422,3424,3426,3429,3432,3435,3437],{"class":71,"line":135},[69,3406,2259],{"class":116},[69,3408,3409],{"class":120}," double",[69,3411,125],{"class":124},[69,3413,2209],{"class":128},[69,3415,327],{"class":350},[69,3417,205],{"class":75},[69,3419,467],{"class":116},[69,3421,3353],{"class":128},[69,3423,327],{"class":350},[69,3425,831],{"class":193},[69,3427,3428],{"class":350},") ",[69,3430,3431],{"class":124},"*",[69,3433,3434],{"class":355}," 2",[69,3436,381],{"class":350},[69,3438,149],{"class":75},[69,3440,3441,3443,3445,3447],{"class":71,"line":152},[69,3442,2375],{"class":260},[69,3444,740],{"class":75},[69,3446,3409],{"class":193},[69,3448,2394],{"class":75},[69,3450,3451],{"class":71,"line":165},[69,3452,307],{"class":75},[46,3454,3456],{"id":3455},"_8-总结","8. 总结",[3458,3459,3460,3476],"table",{},[3461,3462,3463],"thead",{},[3464,3465,3466,3470,3473],"tr",{},[3467,3468,3469],"th",{},"场景",[3467,3471,3472],{},"做法",[3467,3474,3475],{},"收益",[3477,3478,3479,3497,3512,3531,3548,3567,3580],"tbody",{},[3464,3480,3481,3486,3494],{},[3482,3483,3484],"td",{},[403,3485,335],{},[3482,3487,3488,3491,3492],{},[28,3489,3490],{},"defineProps\u003C{...}>()"," + ",[28,3493,223],{},[3482,3495,3496],{},"编译时类型检查，自动生成运行时声明",[3464,3498,3499,3504,3509],{},[3482,3500,3501],{},[403,3502,3503],{},"Emits",[3482,3505,3506],{},[28,3507,3508],{},"defineEmits\u003C{(e: 'change', v: string): void}>()",[3482,3510,3511],{},"事件参数类型校验，调用提示",[3464,3513,3514,3519,3528],{},[3482,3515,3516],{},[403,3517,3518],{},"模板 ref",[3482,3520,3521,3524,3525],{},[28,3522,3523],{},"ref\u003CHTMLInputElement>",", ",[28,3526,3527],{},"ref\u003CInstanceType\u003Ctypeof Comp>>",[3482,3529,3530],{},"安全访问 DOM \u002F 组件实例",[3464,3532,3533,3538,3545],{},[3482,3534,3535],{},[403,3536,3537],{},"依赖注入",[3482,3539,3540,3491,3542],{},[28,3541,1343],{},[28,3543,3544],{},"provide\u002Finject",[3482,3546,3547],{},"类型安全的跨层级通信",[3464,3549,3550,3555,3560],{},[3482,3551,3552],{},[403,3553,3554],{},"全局属性",[3482,3556,3557,3559],{},[28,3558,1956],{}," 扩展",[3482,3561,3562,3563,3566],{},"为 ",[28,3564,3565],{},"this.$xxx"," 或模板中的全局变量提供类型",[3464,3568,3569,3574,3577],{},[3482,3570,3571],{},[403,3572,3573],{},"Pinia",[3482,3575,3576],{},"Setup Store 自动推导",[3482,3578,3579],{},"几乎零配置类型安全",[3464,3581,3582,3587,3592],{},[3482,3583,3584],{},[403,3585,3586],{},"Composables",[3482,3588,3589,3590,3329],{},"显式返回类型、泛型约束、",[28,3591,3328],{},[3482,3593,3594],{},"可复用逻辑的类型安全与灵活性",[24,3596,3597],{},"借助 TypeScript，Vue 3 的开发体验大幅提升，不仅减少了运行时错误，还让重构和协作更加可靠。建议在项目中全面启用 TypeScript，并遵循上述模式。",[3599,3600,3601],"h2",{"id":3601},"参考文献",[24,3603,3604],{},"以下链接在编写时均可正常访问：",[3458,3606,3607,3617],{},[3461,3608,3609],{},[3464,3610,3611,3614],{},[3467,3612,3613],{},"资料",[3467,3615,3616],{},"说明",[3477,3618,3619,3632,3644],{},[3464,3620,3621,3629],{},[3482,3622,3623],{},[33,3624,3628],{"href":3625,"rel":3626},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Ftypescript\u002Foverview.html",[3627],"nofollow","Vue：TypeScript 支持",[3482,3630,3631],{},"总览",[3464,3633,3634,3641],{},[3482,3635,3636],{},[33,3637,3640],{"href":3638,"rel":3639},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Ftypescript\u002Fcomposition-api.html",[3627],"Vue：\u003Cscript setup> + TS",[3482,3642,3643],{},"组合式 API",[3464,3645,3646,3653],{},[3482,3647,3648],{},[33,3649,3652],{"href":3650,"rel":3651},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Flanguage-tools\u002Ftree\u002Fmaster\u002Fpackages\u002Ftsc",[3627],"vue-tsc",[3482,3654,3655],{},"类型检查 CLI",[3657,3658,3659],"style",{},"html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":65,"searchDepth":106,"depth":106,"links":3661},[3662,3663,3664,3665,3667,3669,3670,3671,3672],{"id":48,"depth":113,"text":49},{"id":503,"depth":113,"text":504},{"id":889,"depth":113,"text":890},{"id":1339,"depth":113,"text":3666},"4. 依赖注入的类型安全：InjectionKey\u003CT>",{"id":1952,"depth":113,"text":3668},"5. 全局类型扩展：ComponentCustomProperties",{"id":2152,"depth":113,"text":2153},{"id":2788,"depth":113,"text":2789},{"id":3455,"depth":113,"text":3456},{"id":3601,"depth":106,"text":3601},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FVue\u002Ftypescript","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FVue\u002Ftypescript.md","md",{"items":3678},[3679,3683,3687,3691,3695,3699],{"path":3680,"title":3681,"description":3682,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fassets","资源优化","图片懒加载、按需引入与 Web Vitals 监控。见 HTML 图片、CSS 字体优化。",{"path":3684,"title":3685,"description":3686,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fstatus","状态管理：Pinia 与 Vuex","Pinia 是 Vue 官方推荐的状态管理库（Vue 3 新项目默认选型）。Vuex 4 仍可与 Vue 3 配合，用于维护旧项目。见 Vue 基础。",{"path":3688,"title":3689,"description":3690,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fecology","Vue 生态关键库深度集成","VueUse、Vite 与 Nuxt 是 Vue 3 生态中常用的效率与工程化方案。概览见 Vue 基础。",{"path":3692,"title":3693,"description":3694,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Ftrack","依赖收集与派发更新机制","说明 Vue 3 中 track \u002F trigger 与 targetMap 的工作方式。前置：v2-v3 差异。",{"path":3696,"title":3697,"description":3698,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftest","测试策略","Vue 应用常用 Vitest + @vue\u002Ftest-utils 做单元\u002F组件测试，Playwright 或 Cypress 做 E2E。见 Vue 基础。",{"path":3700,"title":3701,"description":3702,"category":10,"score":165},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fdesign","组合式 API 与逻辑复用设计模式","组合式 API 与 Composables 是 Vue 3 推荐的逻辑组织方式。概览见 Vue 基础。",{"series":3704,"title":12,"items":3705,"index":1254,"prev":3753,"next":3754},"booklet\u002Fframe\u002Fvue",[3706,3708,3710,3714,3716,3718,3722,3726,3730,3734,3738,3742,3744,3746,3748,3749],{"path":3680,"title":3681,"date":3707,"pinned":15},"2025-11-06",{"path":35,"title":36,"date":3709,"pinned":15},"2021-07-29",{"path":3711,"title":3712,"date":3713,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild","编译与打包优化","2021-08-02",{"path":3700,"title":3701,"date":3715,"pinned":15},"2024-06-16",{"path":3688,"title":3689,"date":3717,"pinned":15},"2025-08-26",{"path":3719,"title":3720,"date":3721,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fproject","工程化实践","2021-07-20",{"path":3723,"title":3724,"date":3725,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops","组件通信与跨层级设计模式","2023-03-23",{"path":3727,"title":3728,"date":3729,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fproxy","响应式进阶","2023-03-21",{"path":3731,"title":3732,"date":3733,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender","渲染机制与编译原理","2021-09-23",{"path":3735,"title":3736,"date":3737,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frouter","路由与权限控制","2021-09-12",{"path":3739,"title":3740,"date":3741,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fruntime","运行时优化","2021-06-10",{"path":3684,"title":3685,"date":3743,"pinned":15},"2025-10-11",{"path":3696,"title":3697,"date":3745,"pinned":15},"2024-10-23",{"path":3692,"title":3693,"date":3747,"pinned":15},"2025-01-13",{"path":7,"title":8,"date":14,"pinned":15},{"path":3750,"title":3751,"date":3752,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fv2-v3","Vue 2 与 Vue 3 响应式差异","2022-07-06",{"path":3692,"title":3693,"date":3747,"pinned":15},{"path":3750,"title":3751,"date":3752,"pinned":15}]