React Router 的 isCookie 类型守卫:判断 Cookie 对象的原理、源码与实战用法
React Router 的 isCookie 类型守卫判断 Cookie 对象的原理、源码与实战用法【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-routerisCookie是 React Router服务端运行时代提供的一个工具函数用于判断某个值是否是一个 React Router Cookie 对象。本篇文章围绕 isCookie 官方文档 展开深入其底层类型守卫实现、内部调用链Session 存储体系并给出可直接复制运行的用法示例帮助你在框架framework与数据data两种模式下正确识别与管理 Cookie。isCookie 是什么在 React Router 的服务端编程模型中Cookie 并不是一个简单的字符串或键值对字典而是一个带有元信息与行为的对象Cookie它通过parse()与serialize()方法完成 HTTP Cookie 头与业务值之间的双向转换。isCookie就是这个对象体系的“身份证校验器”传入任意值object返回true表示它是 React Router 的Cookie对象返回false则表示它不是例如普通对象、数组、字符串、布尔值等。文档给出的语义非常简洁见 isCookie.md 的 Summary 部分Returnstrueif a value is a React RouterCookieobject.若值为 React Router 的Cookie对象则返回true。它适用的模式标记为framework与data对应 React Router v7 中需要在服务端处理会话与 Cookie 的框架模式和以 data router数据路由为核心的模式纯客户端声明式SPA场景一般不需要直接使用它。签名一个 TypeScript 类型守卫函数isCookie的函数类型被单独定义并导出为IsCookieFunction在 IsCookieFunction.md 中有完整说明type IsCookieFunction (object: any) object is Cookie;注意签名中的object is Cookie这是一个type predicate类型谓词。这意味着isCookie不仅仅是返回一个布尔值当它在条件分支中使用时TypeScript 会自动把判定通过后的值收窄为Cookie类型例如import { createCookie, isCookie } from react-router; function handleCookie(value: unknown) { if (isCookie(value)) { // 此处 TypeScript 已把 value 收窄为 Cookie 类型 // 可以直接访问 name / isSigned或调用 parse() / serialize() console.log(value.name, value.isSigned); return value; } throw new Error(传入的不是 Cookie 对象); }因此isCookie的返回值既是运行时判断结果也承载编译期的类型信息——这正是它在内部 Session 存储代码中被频繁用于“鸭子类型分发”的原因。判定规则源码中的五个逐条校验isCookie的实际实现位于 packages/react-router/lib/server-runtime/cookies.ts。它并不依赖instanceof而是采用“鸭子类型duck typing”逐条探测对象的形状export const isCookie: IsCookieFunction (object): object is Cookie { return ( object ! null typeof object.name string typeof object.isSigned boolean typeof object.parse function typeof object.serialize function ); };对照 Cookie 接口定义可以把五个条件与接口字段一一对应校验条件对应 Cookie 字段说明object ! null—排除null与undefined两者直接返回falsetypeof object.name stringreadonly name: stringCookie 名称必须是字符串它决定Cookie/Set-Cookie头中的键名typeof object.isSigned booleanreadonly isSigned: boolean是否配置了用于签名校验的secretstypeof object.parse functionparse(cookieHeader, options)能把原始Cookie头解析出本 Cookie 的值typeof object.serialize functionserialize(value, options)能把业务值编码为Set-Cookie头需要特别强调的是name的取值并非该校验的关注点只要五个条件的类型成立即判定为 Cookie。从实现层面可以推断这能兼容由createCookie之外的渠道构造、但结构上符合Cookie约定的对象反过来说一个恰好拥有name字符串、isSigned布尔值和两个同名方法的“看起来像 Cookie”的对象也会被判定为true鸭子类型的典型取舍。此外判定中并不检查expires因为它是可选字段。由 createCookie 产生的标准 Cookie 对象与isCookie配对出现的是createCookie其标准用法与默认值在 cookies.ts 与 createCookie.md 中均有记录import { createCookie } from react-router; const theme createCookie(theme); const session createCookie(session, { maxAge: 60 * 60 * 24 * 7, // 7 天 secrets: [s3cret1], // 一旦提供 secretsisSigned 即为 true });createCookie对选项做了两处默认填充源码中可见path: /与sameSite: lax。默认情况下未传secretsisSigned返回false只有传入一个或多个密钥时才启用签名。由于createCookie返回的对象严格具备name、isSigned、parse、serialize这四个成员因此isCookie(createCookie(theme))必然为true这一点也被官方测试所验证见下文“测试与验证”一节。真实调用场景Session 存储中的内部复用isCookie的最大价值体现在它被 React Router 自身大量复用例如在两类 Session 存储工厂中它被用来判断外部传入的cookie参数到底是“一个现成的 Cookie 对象”还是“一份待创建 Cookie 的选项”。createSessionStorage通用存储策略在 sessions.ts 的createSessionStorage中export function createSessionStorageData SessionData, FlashData Data({ cookie: cookieArg, createData, readData, updateData, deleteData, }: SessionIdStorageStrategyData, FlashData): SessionStorageData, FlashData { let cookie isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || __session, cookieArg); // ... }逻辑非常清晰如果cookieArg已经是 Cookie 对象就直接采用否则把它当作选项用默认名__session兜底调用createCookie。isCookie在这里承担了“入参归一化”的分支判断。createCookieSessionStorage纯 Cookie 会话在 sessions/cookieStorage.ts 中createCookieSessionStorage采用了完全相同的模式export function createCookieSessionStorage Data SessionData, FlashData Data, ({ cookie: cookieArg }: CookieSessionStorageOptions {}): SessionStorage Data, FlashData { let cookie isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || __session, cookieArg); // ... }可以看到isCookie是打通“Cookie 直接传入”与“选项自动构建”两种 API 形态的枢纽。React Router 中内存、Cloudflare KV、Node、Architect 等各类 SessionStorage 适配器均建立在这套结构之上如 createMemorySessionStorage.md 所描述的 SessionStorage 接口因此isCookie的判定正确性直接影响整个会话体系的健壮性。完整实战示例结合自定义 SessionStorage 使用当你通过createSessionStorage实现自定义存储时可能需要先判断外部传入了 Cookie 对象还是选项import { createCookie, createSessionStorage, isCookie, } from react-router; type UserData { id: string }; type FlashData { error: string }; // 方式一传入已经创建好的 Cookie 对象 const myCookie createCookie(custom-session, { secrets: [abc123] }); const storageA createSessionStorageUserData, FlashData({ cookie: myCookie, // isCookie(myCookie) true直接复用 async createData(data) { /* 持久化 data返回 session id */ }, async readData(id) { /* 依据 id 读回数据 */ }, async updateData(id, data) { /* 依据 id 更新 */ }, async deleteData(id) { /* 依据 id 删除 */ }, }); // 方式二只传名称交给内部 createCookie 自动创建 const storageB createSessionStorageUserData, FlashData({ cookie: { name: custom-session }, // isCookie 判定为 false走 createCookie 分支 /* ... 其余三个回调同上 ... */ }); // 方式三什么都不传内部自动以 __session 为名创建 Cookie const storageC createSessionStorageUserData, FlashData({ /* ... 其余三个回调同上 ... */ });在守卫逻辑中自主判断如果只是希望确认某个值是否是合法 Cookie 对象配合上文类型收窄即可import { isCookie } from react-router; function describe(value: unknown): string { if (isCookie(value)) { return 这是一个名为 ${value.name} 的 Cookie签名开关${value.isSigned}; } return 这不是一个 React Router Cookie 对象; } console.log(describe({})); // 这不是一个 React Router Cookie 对象边界情况与易混淆点空值与基础类型null、undefined、、true、[]、{}等均判定为false这是官方测试明确覆盖的场景见下文。不要用typeof value object替代Cookie判定要求的是对象上存在四个特定形状成员单纯“是对象”远远不够。与isSession区分isSession判断的是Session对象带有id与data而isCookie判断的是会话赖以持久化的Cookie对象二者用途不同详见 isSession.md。运行时语义parse与serialize都是异步方法返回Promise如果你要构造与createCookie行为一致的对象以满足isCookie校验需自行保证这两点。测试与验证仓库在 packages/react-router/tests/server-runtime/cookies-test.ts 中为isCookie编写了专门的测试用例describe(isCookie, () { it(returns true for Cookie objects, () { expect(isCookie(createCookie(my-cookie))).toBe(true); }); it(returns false for non-Cookie objects, () { expect(isCookie({})).toBe(false); expect(isCookie([])).toBe(false); expect(isCookie()).toBe(false); expect(isCookie(true)).toBe(false); }); });这些用例直接验证了isCookie(createCookie(...)) true同时确认空对象、数组、空字符串与布尔值均被判为false与源码中的判定逻辑一一对应。同文件中还覆盖了createCookie的解析/序列化行为含空字符串、UTF-8 字符、签名失败返回null等可作为理解 Cookie 生命周期的基础材料。小结isCookie是一个“小函数、大作用”的工具对外它提供语义化的运行时类型守卫配合object is Cookie类型谓词实现编译期类型收窄是 React Router Cookie API 的入口校验器对内它是createSessionStorage、createCookieSessionStorage等会话体系对 cookie 入参做“对象/选项”分发的底层依赖见 sessions.ts 与 cookieStorage.ts。当你需要在框架模式或 data 模式下编写自定义 SessionStorage、处理 Cookie 类型的入参或守卫外部传入的数据时都可以优先考虑使用isCookie它让代码既具备清晰的语义又天然获得 TypeScript 的类型安全。相关的完整 API 清单可查阅 utils/index.md更底层的 Cookie 解析与签名细节则可对照 cookies.ts 与 CookieOptions 继续深入。【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →