TypeScript's template literal types let you describe and manipulate string shapes at compile time:
type EventName<T extends string> = `on${Capitalize<T>}`;
// EventName<'click'> = 'onClick'
type ExtractParams<T extends string> =
T extends `${string}:${infer Param}/${infer Rest}`
? Param | ExtractParams<`/${Rest}`>
: T extends `${string}:${infer Param}`
? Param
: never;
type P = ExtractParams<'/users/:id/posts/:postId'>;
// P = 'id' | 'postId'Implement buildRoute(base, path, params):
:paramName segment in path with the corresponding value from paramsbaseError(Missing param: ${key}) if a param is missingbuildRoute('https://api.example.com', '/users/:id/posts/:postId', { id: '42', postId: '7' })
// → 'https://api.example.com/users/42/posts/7'Sample tests