Type safe SolidJS Router `useParam` utility Type

sylvaindethier

Sylvain Dethier

Posted on April 19, 2024

Type safe SolidJS Router `useParam` utility Type

The Type definition

The SolidJS Router useParam<T>() is a generic function that returns the current route parameters. To be type safe we have to specify the type of this parameters. The path for the route already defines this type. To be DRY here is a utility Type that extracts this parameters types from the RouteDefinition.

The route parameters live in a RouteDefinition["matchFilters"] property. We have to extract and convert each of them to string type (parameters are always string type).

// The `matchFilters` of a RouteDefinition describes its Params
type RD$matchFilters<RD extends RouteDefinition> = NonNullable<
  RD["matchFilters"]
>;

// Convert a MatchFilter to string type
type MF$toString<MF extends MatchFilter | undefined> =
  MF extends readonly string[]
    ? MF[number]
    : MF extends RegExp
    ? `${string}`
    : MF extends (s: string) => boolean
    ? `${string}`
    : never;

// Params of a RouteDefinition {[keyof matchFilters]: `${any}`}: Extract and Convert each MatchFilter
type RD$Params<RD extends RouteDefinition> = {
  [k in NonNullable<keyof RD$matchFilters<RD>>]: MF$toString<
    RD$matchFilters<RD>[k]
  >;
};
Enter fullscreen mode Exit fullscreen mode

Finally we want to be able to specify the type each route parameter using the my Refine utility type and Prettify them.

// Refine a defined RouteDefintion
type RD$RouteParams<
  RD extends RouteDefinition,
  tRD extends RouteDefinition = RouteDefinition<RD["path"]>
> = Refine<RD$Params<tRD>, RD$Params<RD>>;

// Refine with user Type and Prettify the result
export type RouteDefinitionParams<
  RD extends RouteDefinition,
  P extends Partial<RD$RouteParams<RD>> = NonNullable<unknown>
> = Prettify<Refine<RD$RouteParams<RD>, P>>;
Enter fullscreen mode Exit fullscreen mode

Example of usage

const path = "/:aNumberParam";
type TRouteDefinition = RouteDefinition<typeof path>;

type TParams = RouteDefinitionParams<TRouteDefinition>;
// or with refined param Type
type TParams = RouteDefinitionParams<TRouteDefinition, {
  aNumberParam: `${number}`;
}>;

const params = useParams<TParams>();
//    ^? Type is { aNumberParam: `${string}` }
//    ^? Type is { aNumberParam: `${number}` } with refined types
Enter fullscreen mode Exit fullscreen mode

TL;DR

You can find the whole TypeScript defintion for this utility type in my Gist solidjs-RouteDefintionParams.d.ts.

What do you think about this utility type ?
How would you improve it ?
Whould you use it or not and why ?

Thank you for reading.

💖 💪 🙅 🚩
sylvaindethier
Sylvain Dethier

Posted on April 19, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related