Как стать автором
Поиск
Написать публикацию
Обновить

Рецепты TypeScript: подстановка параметров в путь

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров5.1K
Всего голосов 17: ↑16 и ↓1+19
Комментарии10

Комментарии 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);
}

Коммент топ
Доберусь до компа, докину в статью, спасибо =)
Полностью решение забирать не буду, иначе всю статью надо будет переписать, но Arg хелпер завезу

Огромное спасибо за Prettify! Теперь можно сильно себе облегчить работу

Зарегистрируйтесь на Хабре, чтобы оставить комментарий