拓冰建站拓冰建站
首页 / 资讯中心 / 正文

TanStack Router isNotFound 函数:识别 404 错误对象并驱动 notFound 边界处理的完整解析

TanStack Router isNotFound 函数识别 404 错误对象并驱动 notFound 边界处理的完整解析【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/routerisNotFound是 TanStack Router 提供的类型守卫函数用于判断任意对象是否是一个NotFoundError。在路由系统的错误处理链路中它是区分404 未找到与普通运行时错误的基石路由匹配、loader/action 归一化、hydration 以及 React/Solid/Vue 各适配层的 not-found 边界都依赖它来路由错误。读完本文你将掌握isNotFound的签名与用法、其单行实现背后的鸭子类型设计以及它在整个 not-found 错误处理流程中的具体调用位置。isNotFound 基础参数、返回值与基本用法isNotFound函数接收单个参数并返回布尔值用于检测一个对象是否为NotFoundError对象。input 参数类型unknown必填待检测的对象判断其是否为NotFoundError返回值类型boolean对象是NotFoundError时返回true否则返回false基本示例import { isNotFound } from tanstack/react-router function somewhere(obj: unknown) { if (isNotFound(obj)) { // obj 在此分支被 TypeScript 收窄为 NotFoundError } }注意示例中的两个细节一是入参可以直接声明为unknown这正符合从任意来源onCatch回调、state.matches的error字段、异常对象等拿到的值无法保证类型的真实场景二是isNotFound是一个 TS 类型守卫obj is NotFoundErrorif分支内obj会被自动收窄可以安全访问obj.data、obj.routeId、obj.headers等属性。源码实现一行鸭子类型判断isNotFound定义在核心包 not-found.ts 中实现只有一行/** Determine if a value is a TanStack Router not-found error. */ export function isNotFound(obj: any): obj is NotFoundError { return obj?.isNotFound true }这个判断之所以成立要结合同文件中notFound工厂函数一起看not-found.tsexport function notFound(options: NotFoundError {}) { ;(options as any).isNotFound true if (options.throw) throw options return options }notFound()在创建错误对象时会隐式地往对象上打一个isNotFound: true标记注意该属性并不出现在NotFoundError类型定义中属于运行时存在、类型不可见的约定isNotFound则通过检查这个标记来识别对象。由此可以得出两点实现事实标记是鸭子类型的而非构造函数检查。NotFoundError在 not-found.ts 中只是一个纯对象类型global、data、throw、routeId、headers以及标记用的内部字段_global没有任何 class 或instanceof可用的原型链。因此只要一个对象拥有isNotFound true属性就会被路由器识别为 not-found 错误——测试用例 hydrate.test.ts 中直接用{ isNotFound: true }构造了这样的字面量对象来模拟服务端序列化后的错误印证了这一设计。该设计对序列化友好。跨服务端/客户端边界SSR、hydration时错误对象需要序列化传输class 实例会丢失原型而普通对象上的布尔标记可以完好保留。这正是 hydration-boundary-chunks.test.ts 中能在服务端和客户端两套路由状态里都成功断言isNotFound(serverRouter.state.matches[1]?.error)/isNotFound(clientRouter.state.matches[1]?.error)为true的原因。isNotFound随notFound一起从核心包统一导出index.ts并由 React 适配层再导出react-router/src/index.tsx因此文档示例中从tanstack/react-router导入是成立的。NotFoundError 与 isNotFound 的配套关系理解了isNotFound判定的对象形状才能理解它的全部用法。NotFoundError的完整定义见 NotFoundErrorType 文档其属性如下属性类型说明globalboolean可选默认false⚠️ 已废弃改用routeId: rootRouteId。为true时 404 由根路由的notFoundComponent处理不再从抛出方冒泡dataany可选传入notFoundComponent的自定义数据throwboolean可选默认false为true时notFound()直接抛出对象而非返回适合让函数返回类型变为never的场景routeIdstring可选指定负责处理该 404 的路由 ID若该路由没有notFoundComponent错误会向上冒泡最终由根路由兜底。默认由抛出方路由处理headersHeadersInit可选服务端处理该 404 时附带的 HTTP 响应头isNotFound在识别错误后这些属性就是你在notFoundComponent、onCatch中可消费的全部信息而routeId的默认值补全逻辑本身就是路由器内部调用isNotFound之后执行的下文详述。路由器内部如何使用 isNotFoundisNotFound并不只是给用户的工具函数它是整个 not-found 错误管道中的关键判定节点。仓库中可以直接看到以下几处调用1. loader 结果归一化客户端与服务端在 load-client.ts 的normalize函数中loader/action 的任何返回值或抛出值都会被分类function normalize(value: unknown, rejected: boolean, routeId?: string): RawLoaderOutcome { if (isRedirect(value)) { return [REDIRECTED, value] } if (isNotFound(value)) { value.routeId || routeId return [NOT_FOUND, value] } // ... }这里有两个重要行为loader 中return notFound(...)或throw notFound(...)都会被识别为NOT_FOUND结果同时如果调用方没有显式指定routeId这里会用当前匹配的routeId补全||。服务端在 load-server.ts 中有同样的判断保证 SSR 与客户端行为一致。2. 路由匹配层转发 404 而非渲染错误组件React 适配层的 Match.tsx 在onCatch中明确区分了两类错误onCatch{(error, errorInfo) { // Forward not found errors (we dont want to show the error component for these) if (isNotFound(error)) { error.routeId ?? match.routeId throw error } // 普通错误才走 errorComponent / routeOnCatch }}注释说明得很直接not-found 错误不应被当前路由的errorComponent捕获而是要继续向外抛出交给最近的notFoundComponent边界同文件下方的ResolvedNotFoundBoundary处理普通错误则留在错误边界内。error.routeId ?? match.routeId再次体现了由抛出方路由兜底的默认策略。3. 全局 CatchNotFound 边界的分支判定CatchNotFound 是兜底的 404 边界组件其onCatch与errorComponent回调中反复使用isNotFound(error)做分支是 404 就渲染fallback否则把错误继续throw出去交给上层错误边界。该组件对服务端渲染路径和客户端 hydration 路径各有一套等价实现判定逻辑完全一致。Solidsolid-router/src/not-found.tsx与 Vuevue-router/src/not-found.tsx适配层同样导出了isNotFound并在各自的 not-found 实现中使用说明这一判定机制是框架无关的核心能力。4. 参数校验路径上的错误分流在 router.ts 的严格参数提取extractStrictParams中捕获到的异常会先过isNotFound/isRedirect检查若抛出的其实是 not-found 或 redirect原样保留否则包装成PathParamError。这保证了即使参数校验抛出特殊错误对象也不会被误包装而失去 404 语义。实战用法在错误边界与路由处理器中使用结合上述内部机制以下是isNotFound的典型应用场景。在 onCatch 中区分 404 与运行时错误import { isNotFound } from tanstack/react-router // 全局或路由级 onCatch 中 function onCatch(error: unknown) { if (isNotFound(error)) { // 404可以读取 error.data 做自定义上报或降级 console.log(not found:, error.data) return } // 普通错误走 Sentry 等错误上报 }检查路由状态中的匹配错误路由把最近一次匹配的 error 保存在state.matches上。测试 hydrate.test.ts 展示了标准断言方式expect(isNotFound(serverRouter.state.matches[0]?.error)).toBe(true)在应用中同理可以用isNotFound(match?.error)判断某条 match 当前是否处于 404 状态用于条件渲染或埋点。自定义序列化/日志时保留 404 语义由于判定依据是对象上的isNotFound: true标记如果你需要把错误对象序列化后转发例如跨 worker、日志脱敏务必保留该字段否则接收方将无法识别其 404 语义——issue-5106-hydrated-notfound-boundary.test.ts 正是以{ isNotFound: true }字面量模拟了这种仅带标记的普通对象场景并验证边界仍然能正确接管。使用边界与注意事项判定是宽泛的鸭子类型isNotFound只检查obj?.isNotFound true不做构造或字段完整性校验。任何携带该标记的对象都会被当作 404 处理因此不要在自己的业务对象中随意使用isNotFound这一属性名以免与路由语义冲突。global属性已废弃源码类型中明确标注deprecated应使用routeId: rootRouteId表达由根路由处理 404的意图见 NotFoundErrorType.md 与 not-found.ts。类型守卫收窄依赖 TSobj is NotFoundError的收窄只发生在调用点之后的分支里如果你把错误对象存进宽泛类型的容器再取出来需要重新用isNotFound收窄一次。throw: true与返回值互斥notFound({ throw: true })会直接抛出见 not-found.ts此时不存在返回值下游只会以异常形式见到该对象——isNotFound依然可以识别因为它检查的是同一个标记。小结isNotFound的 API 极简——一个unknown进一个boolean出——但它是 TanStack Router 404 处理体系的分流开关notFound()负责盖章isNotFound: trueloader 归一化、路由匹配的onCatch、CatchNotFound边界以及各框架适配层都用isNotFound来决定这个错误是走 not-found 边界继续冒泡还是落进普通的errorComponent。理解这个标记 守卫的组合就能完整解释 404 从 loader/action 抛出到最终由notFoundComponent接管的整条链路。【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门