以下
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"
通过数组传入的键应该在编译时已知,这样就不会出现拼写错误。并且数组不能大于可用键的数量。这样的事情可能吗?
您可以使用递归为输入和输出路径构建类型:
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"