You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带可选子属性的路由配置实现类型安全映射

TypeScript路由配置对象转换的类型安全实现

问题说明

当前实现存在两处TypeScript类型错误:

  • 递归类型Routes<T[Property]['children']>未处理children为undefined的情况,导致递归无法终止
  • 无法直接将{}赋值给Routes<T>类型的obj,且不想使用@ts-ignore或any规避类型检查

解决方案

1. 修复递归终止条件

通过条件类型判断children是否为有效对象,仅当它是可遍历的路由配置时才继续递归,否则用never终止递归:

type Routes<T extends Record<string, any>> = {
  [K in keyof T]: {
    path: string;
    children: T[K]['children'] extends Record<string, any> ? Routes<T[K]['children']> : never;
  };
};

2. 正确初始化目标对象

使用类型断言结合动态遍历构建对象,避免直接赋值空对象导致的类型不兼容:

function convertRoutes<T extends Record<string, any>>(routes: T): Routes<T> {
  const obj = {} as Routes<T>;
  for (const key in routes) {
    if (Object.prototype.hasOwnProperty.call(routes, key)) {
      const route = routes[key];
      obj[key] = {
        path: route.path,
        children: route.children ? convertRoutes(route.children) : ({} as never)
      };
    }
  }
  return obj;
}

完整可运行代码

// 基础路由配置类型
type RouteConfig = {
  path: string;
  children?: Record<string, RouteConfig>;
};

// 转换后的目标类型(修复递归终止逻辑)
type Routes<T extends Record<string, RouteConfig>> = {
  [K in keyof T]: {
    path: string;
    children: T[K]['children'] extends Record<string, RouteConfig> ? Routes<T[K]['children']> : never;
  };
};

// 转换函数(修复对象初始化类型问题)
function convertRoutes<T extends Record<string, RouteConfig>>(routes: T): Routes<T> {
  const obj = {} as Routes<T>;
  for (const key in routes) {
    if (Object.prototype.hasOwnProperty.call(routes, key)) {
      const route = routes[key];
      obj[key] = {
        path: route.path,
        children: route.children ? convertRoutes(route.children) : ({} as never)
      };
    }
  }
  return obj;
}

// 示例用法
const appRoutes = {
  home: { path: '/' },
  about: { path: '/about', children: { team: { path: '/team' } } }
};

const convertedRoutes = convertRoutes(appRoutes);
// 类型检查正常:convertedRoutes.about.children.team.path 会被正确推断为 string 类型

核心优化点

  • 递归类型通过T[K]['children'] extends Record<string, RouteConfig>做条件判断,当children为undefined时,自动终止递归
  • 使用as Routes<T>对空对象做类型断言,同时通过遍历动态填充属性,确保最终返回值完全符合目标类型
  • 处理children为undefined时,用({} as never)匹配类型要求,避免类型不兼容报错

内容的提问来源于stack exchange,提问作者Johannes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:35:23