Home > Software engineering >  Conditional type with inference and extends clause on TS 4.6
Conditional type with inference and extends clause on TS 4.6

Time:09-15

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.

  • Related