基于键数组合并路径段的类型安全函数

问题描述 投票:0回答:1

以下

Paths
类型表示由路径段分割的多个 url 路径。

type PathSegment = {
    path: string;
    children: Paths;
}

type Paths = Record<string, PathSegment | string>;

以下是匹配此类型的示例对象:

const paths: Paths = {
    home: "/",
    profile: "/profile",
    settings: {
        path: "/settings",
        children: {
            general: "/general",
            account: "/account",
        }
    }
}

是否可以创建一个函数,通过提供应合并的路径的键,以类型安全的方式将路径段合并在一起?例如,给定上面的

paths
对象,我可以执行以下操作:

const accountSettingsPath = mergePathSegments(paths, ["settings", "account"]);
console.log(accountSettingsPath); // outputs "/settings/account"

通过数组传入的键应该在编译时已知,这样就不会出现拼写错误。并且数组不能大于可用键的数量。这样的事情可能吗?

javascript typescript typescript-generics
1个回答
0
投票

您可以使用递归为输入和输出路径构建类型:

游乐场

type PathSegment = {
    path: string;
    children: Paths;
}

type Paths = Record<string, PathSegment | string>;

const paths = {
    home: "/",
    profile: "/profile",
    settings: {
        path: "/settings",
        children: {
            general: "/general",
            account: "/account",
        }
    }
} as const satisfies Paths;

type Breadcrumbs<T extends Paths> = 
  {[K in keyof T]: T[K] extends string ? 
    [K] : 
    T[K] extends PathSegment ? 
      [K, ... Breadcrumbs<T[K]['children']>] : 
      never 
  }[keyof T];

type MakePath<T extends Paths, B extends Breadcrumbs<T>> = 
  {[K in B[0]]: T[K] extends string ? 
    T[K] : 
    T[K] extends PathSegment ?  
      `${T[K]['path']}${B extends [string, ...infer C] ? C extends Breadcrumbs<T[K]['children']> ? MakePath<T[K]['children'], C> : '' : ''}` : 
      never 
  }[B[0]];


declare function mergePathSegments<T extends Paths, const B extends Breadcrumbs<T>>(paths: T, breadcrumbs: B): MakePath<T, B> extends `${infer A}` ? A : string

const accountSettingsPath = mergePathSegments(paths, ["settings", "general"]); // "/settings/account"
console.log(accountSettingsPath); // outputs "/settings/account"
© www.soinside.com 2019 - 2024. All rights reserved.