I wrote the following types with TS 4.7 in mind :
const routes = {
foo: '/foo/:paramFoo',
bar: '/bar/:paramFoo/:paramBar',
baz: '/baz/baz2/:paramFoo/:paramBar',
} as const;
type Routes = typeof routes;
type RouteParser<S extends string> =
string extends S ? string[] :
S extends '' ? [] :
S extends `${infer T}/:${infer U}` ? [T, ...RouteParser<U>] : [S];
type RouteParams<S extends string> = RouteParser<S> extends [infer path, ...infer params extends string[]] ? { // can't do that in TS 4.6
[K in params[number]]: string;
} : { [x in string]: string; };
function navigateTo<T extends keyof Routes, U extends Routes[T]>(route: U, params: RouteParams<U>) {
let actualRoute: string = route;
Object.keys(params ?? {}).forEach((param) => {
actualRoute = actualRoute.replace(`:${param}`, param in params ? params[param] : '');
})
console.log(actualRoute);
}
navigateTo(routes.foo, { paramFoo: 'foo' })
navigateTo(routes.bar, { paramFoo: 'foo', paramBar: 'bar' })
navigateTo(routes.baz, { paramFoo: 'foo', paramBar: 'bar' })
navigateTo(routes.baz, { paramFoo: 'foo', paramBar: 'bar' })
I am currently stuck on an Angular 13 project though, and I can't use the extends
clause feature brought by TS 4.7
How could I rewrite it to work with TS 4.6 ?
Playground (using version 4.6)
CodePudding user response:
In 4.6, we would write the following:
type RouteParams<S extends string> = RouteParser<S> extends [infer path, ...infer params] ? params extends string[] ? {
[K in params[number]]: string;
} : { [x in string]: string; } : { [x in string]: string; };
Which is why we have the new extends in infer clauses in 4.7.
You have to move the params extends string[]
into its own conditional.