Home > Software engineering >  Typescript Type - extract required function values from a string (generics)
Typescript Type - extract required function values from a string (generics)

Time:09-27

I've got the following PAGES and I would like to create helper functions for each to resolve each path. This means replacing the sections with ':'.

The helper functions need to have strict types depending on the params needed to be resolved.

Is there a way of adding a type to the below code to only allow parameters the selected function needs? ie. Replace the any

Any help would be appreciated.

const PAGES = {
  TEST: 'YO/:id/again/:param', // params 'id' and 'param' required.
  TEST2: 'YO2/:hello/:yo' // params 'hello' and 'yo' required.
} as const

type ValidParams = any; //replace 'any' and allow only valid params.

type HelperFunctions<T> = { [K in keyof T]: ( params: ValidParams ) => string }

const createHelperFunctions = <P extends Record<string, string>( pages: P ): HelperFunctions<P> => {
   const pageMap = { ...pages };
   const helpers: Record<any, any> = {};

   (Object.keys(pageMap) as (keyof P)[]).forEach((key) => {

      // only accept valid params.
      helpers[key] = ( params: ValidParams ) => {
         const route = routeMap[key];
         return '' // will call another function to replace params in the route.      
      }
   })

   return helpers as ReturnType<typeof createHelperFunctions<P>>;
}


const helpers = createHelperFunctions( PAGES );

// no errors and return 'YO/value-1/again/value-2'
helpers.TEST({ id: 'value-1', param: 'value-2' });

// no errors and return 'YO2/value-2/value-1'
helpers.TEST2({ yo: 'value-1', hello: 'value-2' });

// should get type error 
helpers.TEST({ yo: 'value' });

// should get type error 
helpers.TEST({ yo: 'value', hello: 'value' });

// should get type error 
helpers.TEST({ yo: 'value', hello: 'value', id: 'value', param: 'value' });

// should get type error 
helpers.TEST({});

CodePudding user response:

Let's start with the ValidParams type. Given a string literal P, it should generate an object type containing all the params of P. We can achieve this using template literal types.

type ValidParams<P extends string> = 
  P extends `${string}:${infer U}/${infer R}`
    ? Record<U, string> & ValidParams<R>
    : P extends `${string}:${infer U}`
      ? Record<U, string>
      : {}

This type can now be used in the HelperFunctions like this:

type HelperFunctions<T extends Record<string, string>> = { 
    [K in keyof T]: (params: ValidParams<T[K]>) => string 
}

This will give you the strict typing for the TEST method.

Playground


I wasn't sure if you want the return type to be strictly typed to be a string literal too. But anyways, here is that monster:

Playground

  • Related