如何为嵌套路由函数定义TypeScript类型?
如何为嵌套路由函数定义TypeScript类型?
我太懂这种迁移时卡壳的感觉了——这种可以无限嵌套的路由函数类型,确实容易让TypeScript新手(甚至老手)挠头。先回顾下你的场景:
const root: Route = () => 'root' root.child = () => `${root()}/child` root.child.grandchild = () => `${root.child()}/grandchild`
你尝试的type Route = { (): string; [key: string]: Route }思路方向是对的,但问题出在TypeScript的严格校验上:直接把普通的() => string函数赋值给Route类型时,TS会认为这个函数不具备索引签名要求的嵌套属性,从而抛出错误。
解决思路
我们需要让TS认可:一个返回字符串的函数,同时可以被扩展出任意数量的同类型嵌套属性。这里有两种实用的实现方案:
方案1:交叉类型+工具函数包装
先定义正确的交叉类型,再通过工具函数把普通函数"升级"成Route类型,绕过直接赋值的类型校验:
// 定义Route类型:既是返回string的函数,又能拥有任意字符串键的Route子属性 type Route = (() => string) & Record<string, Route>; // 工具函数:将普通函数断言为Route类型,告诉TS它后续会被扩展嵌套属性 function createRoute(fn: () => string): Route { return fn as Route; } // 现在使用完全符合类型要求 const root = createRoute(() => 'root'); root.child = createRoute(() => `${root()}/child`); root.child.grandchild = createRoute(() => `${root.child()}/grandchild`); // 测试调用,类型推断完全正常 console.log(root()); // "root" console.log(root.child.grandchild()); // "root/child/grandchild"
方案2:接口定义(本质和方案1一致)
如果你更习惯用接口语法,也可以这样写:
interface Route { (): string; [key: string]: Route; } // 同样用工具函数辅助创建 function createRoute(fn: () => string): Route { return fn as Route; } // 使用方式和方案1完全相同 const root = createRoute(() => 'root'); root.child = createRoute(() => `${root()}/child`);
为什么之前的写法不行?
你之前的类型定义逻辑本身没错,但TypeScript对函数类型的赋值有严格校验:普通的() => string函数并不自动具备Route类型要求的索引签名属性。通过createRoute的类型断言,我们相当于给TS打了个"招呼":这个函数后续会被扩展嵌套属性,放心把它当作Route类型处理。
内容的提问来源于stack exchange,提问作者Guilherme Baron
相关产品推荐
相关产品推荐

