[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site":3,"post-biao-ge-cha-cao-li-de-row-shi":59,"related-biao-ge-cha-cao-li-de-row-shi":78},{"name":4,"url":5,"description":6,"bio":7,"avatar":8,"skills":9,"tools":16,"social":34,"hero":47,"heatmap":52,"icp":55,"police":56,"policeIcon":57,"shortName":58},"时过境迁技术笔记","https:\u002F\u002Fhsgjq.top","一个记录前端与 Node 实践的个人博客，内容围绕 Vue、Nuxt、NestJS 与工程化展开，附源码级的原理笔记。","一名热爱技术的全栈开发者，专注 TypeScript 与 Web 工程化，习惯把踩过的坑和思考记录在这里。","\u002Fuploads\u002Fc485c101-179e-48db-96d1-238693784c38.jpg",[10,11,12,13,14,15],"TypeScript","Vue 3","Nuxt","NestJS","Node.js","工程化",[17,23,28],{"items":18,"title":22},[19,20,21],"Cursor","Git","Chrome DevTools","开发工具",{"items":24,"title":27},[25,26],"Vite","npm","构建工具",{"items":29,"title":33},[30,31,32],"Docker","CI\u002FCD(GitHub Actions)","Vercel","部署运维",[35,39,43],{"href":36,"icon":37,"label":38},"https:\u002F\u002Fgithub.com\u002Fhsgjq","github","GitHub",{"href":40,"icon":41,"label":42},"2971861643@qq.com","mail","邮箱",{"href":44,"icon":45,"label":46},"\u002Frss.xml","rss","RSS",{"lines":48,"subtitle":51},[49,50],"人生若只如初见，","何事秋风悲画扇。","《木兰花·拟古决绝词柬友》",{"enabled":53,"platform":37,"username":54},true,"hsgjq","桂ICP备2024046985号","桂公网安备45011002000103号","\u002Fuploads\u002F72c67ef3-bc86-4b64-b0df-0aba71065050.png","时过境迁",{"slug":60,"title":61,"excerpt":62,"date":63,"updatedAt":64,"tags":65,"content":67,"series":68,"seriesIndex":69,"seriesNav":70,"prev":72,"next":75},"biao-ge-cha-cao-li-de-row-shi","表格插槽里的 row 是宽类型：TS7053","组件库插槽给的 row 是 Record\u003Cstring, any> 之类，取字段时报错的是索引那一行。枚举映射写成按字段值的函数最省事。","2026-04-10","2026-10-17",[10,66],"Vue","后台表格的列要用插槽渲染，代码很普通：\n\n```html\n\u003Cel-table-column prop=\"status\">\n  \u003Ctemplate #default=\"{ row }\">\n    {{ statusText[row.status] }}\n  \u003C\u002Ftemplate>\n\u003C\u002Fel-table-column>\n```\n\n报错 TS7053：无法用 string 类型的表达式索引 { } 这个类型。\n\n原因拆开看是两层。第一层，组件库给插槽作用域的类型是宽的，row 上有什么它不知道，row.status 推出来是 string 而不是我那几个枚举值之一。第二层，statusText 是个对象字面量，它的类型只有那几个键，用 string 去索引就报错。\n\n三种解法我都试过：\n\n(statusText as Record\u003Cstring, string>)[row.status] —— 有效，但每个插槽都要写一次断言，很脏。\n\n给 statusText 加显式类型 Record\u003CStatus, string>，同时把 row 断言成 { status: Status }。两处断言，比上面少一个，但还是断言。\n\n我最后用的：把映射写成按字段值的函数，在 script 里定义好，插槽只调它。\n\n```ts\ntype Status = 'draft' | 'published'\nconst statusText: Record\u003CStatus, string> = { draft: '草稿', published: '已发布' }\nconst textOf = (s: Status) => statusText[s]\n```\n\n插槽里写 textOf(row.status as Status)。断言只剩一处，而且新增状态时编译期会在 statusText 上报缺键——这才是我要的效果：错误暴露在字典那一行，而不是散在模板里。\n\n还有一个 TS2345：给组件传 :data=\"list\"，list 是接口返回的 any[]，赋给要求 Article[] 的 prop 时不报错，因为 any 兼容一切。所以接口层返回类型才是根，表格这层只是把问题显形了。","TypeScript 补课",6,[71],{"slug":60,"title":61,"seriesIndex":69},{"slug":73,"title":74},"yao-bu-yao-wei-xi-lie-dan-du","要不要为系列单独建一张表",{"slug":76,"title":77},"rss-he-sitemap-shi-zen-me-bei-pa","RSS 和 sitemap 是怎么被爬虫看到的",[79,88,94,100,105],{"slug":80,"title":81,"excerpt":82,"date":83,"tags":84},"gang-deng-lu-jiu-guo-qi-yi-ci","一个 401，查出四个前端机制：缓存回放、隐藏页的 rAF、百分比圆角、缓动过冲","响应头里的 token 被 304 原样回放，把刚签发的新 token 顶掉，表现成刚登录就过期。顺带记三个前端细节：隐藏标签页里 rAF 不执行、扁盒子的 50% 圆角是胶囊、缓动曲线的过冲只有 0.0008。","2026-10-13",[85,86,66,87],"CSS","JavaScript","浏览器",{"slug":89,"title":90,"excerpt":91,"date":92,"tags":93},"sou-suo-mian-ban-ctrl-k-he-shu","搜索面板：Ctrl+K 和输入框防抖","全局快捷键要判断输入焦点、Esc 关闭、上下键移动选中项。无障碍那部分我补了第二轮才加上。","2026-03-15",[66],{"slug":95,"title":96,"excerpt":97,"date":98,"tags":99},"dian-xiang-mu-ye-mian-jiu-si-yi","点「项目」页面就死：一次客户端无限重定向","为了保留旧地址大小写加的一条跳转规则，被注册成了客户端路由；路由匹配不区分大小写，于是它自己跳自己。","2026-10-02",[12,87],{"slug":101,"title":102,"excerpt":103,"date":98,"tags":104},"cong-da-bao-shang-chuan-dao-push-ji","从打包上传到 push 即上线：把 CD 接通","私有仓库的镜像包默认也是私有的，健康检查的探测地址在宿主机有 nginx 时会打错地方。两处都是配好之后才验出来的。",[30,15],{"slug":106,"title":107,"excerpt":108,"date":109,"tags":110},"shang-xian-na-tian-yu-ming-zheng-shu","上线那天：域名、证书，和一条我打错的 IP","把 69 打成 96，于是照着\"安全组没放行\"这条错线索查了一整晚。分层排查的前提是先确认敲的是哪扇门。","2026-10-01",[111],"随笔"]