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.
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: