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

在TypeScript条件类型中筛选匹配的组件类

问题核心

你要做的是从Angular路由配置里,精准提取指定组件对应的所有resolve数据类型——本质是TypeScript的类型编程问题。目前卡壳在两个地方:

  1. 用type-fest的IsEqual对比组件类时,总是返回false,完全不符合预期
  2. 自己写的ExtractRouteData类型逻辑不对,没法实现「UserComponent只能访问this.data.user,BookComponent只能访问this.data.book」的需求
为啥IsEqual不好使?

IsEqual是用来做结构类型深度对比的,但Angular组件的构造函数类型(比如typeof UserComponent)属于「名义类型」——它的唯一性是由自身标识决定的,不是结构。用IsEqual去比,会因为展开后原型链之类的细节差异返回false,完全没必要用它,直接比构造函数类型本身就行。

直接能用的解决方案

不用依赖第三方工具,用TypeScript内置的类型工具就能搞定核心逻辑:先从路由数组里筛出组件匹配的项,再提取对应的resolve类型。

完整示例代码

// 模拟Angular的Route类型(和官方类型对齐)
type Route = {
  path: string;
  component: new (...args: any[]) => any;
  resolve?: Record<string, (...args: any[]) => any>;
};

// 你的组件
class UserComponent {}
class BookComponent {}

// 你的resolve函数
const resolveUser = () => ({ id: 1, name: 'Alice' });
const resolveNewUser = () => ({ id: 2, name: 'Bob' });
const resolveBook = () => ({ isbn: '123', title: 'TypeScript Guide' });

// 路由配置(必须用字面量元组,别写成宽泛的Route[],不然TS会丢失具体类型信息)
type AppRoutes = [
  {
    path: 'user/:id',
    component: typeof UserComponent,
    resolve: {
      user: typeof resolveUser
    }
  },
  {
    path: 'user/new',
    component: typeof UserComponent,
    resolve: {
      user: typeof resolveNewUser
    }
  },
  {
    path: 'book/:isbn',
    component: typeof BookComponent,
    resolve: {
      book: typeof resolveBook
    }
  }
];

// 核心类型:提取指定组件对应的resolve数据类型
type ExtractRouteData<Routes extends Route[], TargetComponent> = 
  // 先从路由数组里筛出component匹配的项
  Extract<Routes[number], { component: TargetComponent }> extends infer MatchedRoutes
    ? // 提取这些路由的resolve类型,没有resolve就返回never
      MatchedRoutes extends { resolve: infer R } ? R : never
    : never;

// 测试:UserComponent对应的resolve类型
type UserRouteData = ExtractRouteData<AppRoutes, typeof UserComponent>;
// 结果:{ user: typeof resolveUser } | { user: typeof resolveNewUser }
// 对应组件里this.data.user会被推断为两个resolve函数返回值的联合类型,完全符合预期

// 测试:BookComponent对应的resolve类型
type BookRouteData = ExtractRouteData<AppRoutes, typeof BookComponent>;
// 结果:{ book: typeof resolveBook }
// 组件里只能访问this.data.book,访问this.data.user会直接报错

关键细节

  1. 路由配置必须是字面量元组:如果写成const routes: Route[] = [...],TS会把它当成宽泛的数组类型,丢失每个路由的具体component和resolve信息,类型提取就失效了。
  2. 用Extract替代IsEqual:Extract<Routes[number], { component: TargetComponent }>直接筛选出component字段完全匹配的路由,比IsEqual靠谱得多,因为它直接对比构造函数类型的字面相等。
  3. 自动处理联合路由:如果一个组件对应多个路由(比如UserComponent的两个路由),提取出的resolve类型会自动变成联合类型,组件里的this.data会自动适配所有可能的情况。

可选扩展:合并联合resolve为单一类型

如果你希望把UserComponent的两个resolve类型合并成{ user: typeof resolveUser | typeof resolveNewUser }(而不是两个对象的联合),可以加个小工具类型:

// 把联合类型的resolve合并成单一类型
type MergeResolveUnion<T> = {
  [Key in keyof T]: T extends { [K in Key]: infer Value } ? Value : never;
};

type MergedUserRouteData = MergeResolveUnion<UserRouteData>;
// 结果:{ user: typeof resolveUser | typeof resolveNewUser }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:05:29