首页 > 解决方案 > 将角度路由映射到键是路径属性的类型

问题描述

我有这样的路线

const routes = [
  { path: 'path1' },
  { path: 'path2', children: [{ path: 'path3' }] },
] as const;

我想要一张这样的地图

type map = { path1: {}; path2: { path3: {} } };

那么,如何更正下面的类型以便从上面提供的路线中获取地图?

type MappedRoutes<TRoutes> = {
  [K in keyof TRoutes]: TRoutes[K] extends {children: unknown, path: string, }
    ? {TRoutes[K]['path']: MappedRoutes<TRoutes[K]['children']>}
    : TRoutes[K]['path'];
}

也就是说MappedRoutes<ArrayIndexes<typeof routes>>,如下应该返回{path1: {}; path2: { path3: {} } }

const array = [] as const;
type keyOfArray = keyof typeof array;
type ArrayIndexes<TArray> = Exclude<keyof TArray, keyOfArray>;

type mapped= MappedRoutes<ArrayIndexes<typeof routes>>;

标签: angulartypescriptmappingtypescript-generics

解决方案


我可能会这样写:

type Routes = readonly { path: string, children?: Routes }[];

type MappedRoutes<T extends Routes> = {
    [K in T[number]["path"]]: (Extract<T[number], { path: K }>['children'] extends infer R ?
        R extends Routes ? MappedRoutes<R> extends infer O ? {
            [P in keyof O]: O[P]
        } : never : {} : never)
}

您可以验证它是否以您想要的方式工作(尽管没有干预ArrayIndices):

type Mapped = MappedRoutes<typeof routes>
/* type Mapped = {
    path1: {};
    path2: {
        path3: {};
    };
} */

如果T可分配给Routes, 的数组{path: string, children?: Routes}, 那么MappedRoutes<T>键在T[number]["path"]... 其中T[number]是数组元素类型的并T[number]["path"]集,并且是它们path属性的并集。

然后,对于这些键中的每一个K,我们得到Extract<T[number], {path: K}>['children'],这是children对应于 的属性path。( Extract<T[number], {path: K}>) 采用数组元素的并集并仅提取可分配给 的元素{path: K}。然后我们得到它的children属性)。

我们检查这个children属性。是它Routes本身吗?如果是这样,递归地产生MappedRoutes它。那里发生了相当多的条件类型推断,但这主要是因为我可以将类型存储到类型变量中而不是重写它们。 Rchildren属性,并且O是映射的children属性(如果存在)。我遍历,O以便该Mapped类型急切地递归扩展为其最终形式,而不是像{path1: {}, path2: MappedRoutes<readonly blah blah yuck>}.

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读