Комментарии 10
Спасибо! Как раз было интересно, как это в TanStack Router реализовали, но некогда было код анализировать.
Написали лютый тип, а том в функции написали as ExtractPaths<T>[]. Если бы это проверялось тайп гвардом ещё понимаю. Смысл то какой в этом при таком применении?
Эта функция не является целью статьи и оставлена только для тех, кто хочет прямо сейчас взять и попробовать все на практике.
Но даже в реальном проекте она допустима, тк это "условно библиотечная реализация"
Функция пишется один раз и густо покрывается тестами, поэтому мы спокойно можем быть уверены в ее корректности
Чисто технически, мы можем добавить здесь тайпгарды и, возможно, стоило (мне было лень да и статья не об этом)
Ну и стоит добавить, что ts не умеет типизировать Object.keys - а мы то с вами знаем, что он вернет, верно?)
И смысл в применении остается, тк все вызовы функции будут работать как часы)
ts не умеет типизировать Object.keys
Когда уже починят…
Это принципиально нерешаемая проблема. Объект может быть указан как, например, `{foo: number}`, а по факту там ещё дохрена всего.
Если точно известно, какие ключи имеются, то для таких случаев надо просто запилить свой типизированный Object.keys

Починил для тебя, но явно подменять тайпинг Object.keys не рекомендую =)
На всякий, надо бы выкидывать из набора ключей пустые строки (например, такие будут для "/aaa/:/").
И если ключей не нашлось, то функции generatePath совсем ни к чему обязательность второго параметра. Итого:
type PathParams<T extends string, K extends string = never> =
T extends `${string}/:${infer P}/${infer Right}`
? PathParams<Right, P extends '' ? K : K | P>
: {[P in K]: string};
type Args<T> = {} extends T ? [params?: T] : [params: T];
function generatePath<T extends string>(path: T, ...[params]: Args<PathParams<`/${T}/`>>): string {
return path.replace(/:(\w+)/g, (m, n: string) => (params as Record<string, string>)?.[n] ?? m);
}
Огромное спасибо за Prettify! Теперь можно сильно себе облегчить работу
Рецепты TypeScript: подстановка параметров в путь