{"id":15537688,"url":"https://github.com/atrue/typed-route","last_synced_at":"2026-04-26T20:31:05.849Z","repository":{"id":57383421,"uuid":"287523369","full_name":"Atrue/typed-route","owner":"Atrue","description":"Typesafe routes developed for React Router","archived":false,"fork":false,"pushed_at":"2020-09-18T05:46:26.000Z","size":72,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-18T08:07:32.083Z","etag":null,"topics":["react-router","route","router","typescript","url"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Atrue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-14T12:04:12.000Z","updated_at":"2020-09-18T05:46:29.000Z","dependencies_parsed_at":"2022-09-26T16:50:29.760Z","dependency_job_id":null,"html_url":"https://github.com/Atrue/typed-route","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atrue%2Ftyped-route","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atrue%2Ftyped-route/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atrue%2Ftyped-route/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atrue%2Ftyped-route/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Atrue","download_url":"https://codeload.github.com/Atrue/typed-route/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246113168,"owners_count":20725400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react-router","route","router","typescript","url"],"created_at":"2024-10-02T11:59:08.474Z","updated_at":"2026-04-26T20:31:05.842Z","avatar_url":"https://github.com/Atrue.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003etyped-route\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003eType safe routes developed for React Router\u003c/h4\u003e\n\nQuick example:\n```tsx\n// constants/routes.ts\nimport { typedRoute, routeMap } from 'typed-route';\n\nexport const routes = {\n  list: '/list',\n  item: typedRoute\u003c'id'\u003e('/item/:id'),\n  form: routeMap(typedRoute\u003c'id'\u003e('/form/:id'), {\n    detail: '/detail',\n    subForm: typedRoute\u003c'sub'\u003e('/:sub')\n  })\n};\n\n// routes.tsx\nimport { routes } from './constants/routes';\n\nconst Routes = () =\u003e (\n  \u003cRouter\u003e\n    \u003cRoute exact path={routes.list} component={ListPage} /\u003e\n    \u003cRoute exact path={routes.item} component={ItemPage} /\u003e\n    \u003cRoute exact path={routes.form.detail} component={FormDetailPage} /\u003e\n    \u003cRoute exact path={routes.form.subForm} component={SubFormPage} /\u003e\n  \u003c/Router\u003e\n);\n\n// pages/sub-form.tsx\nimport { InferTypedRoute } from 'typed-route';\nimport { RouteComponentProps } from 'react-router-dom';\nimport { routes } from '../constants/routes';\n\ntype SubFormProps = RouteComponentProps\u003cInferTypedRoute\u003ctypeof routes.form.subForm\u003e\u003e;\n\nconst SubFormPage: React.FC\u003cSubFormProps\u003e = ({ match }) =\u003e (\n  \u003cdiv\u003e\n    Subform params:\n    { match.params.id }\n    { match.params.sub }\n  \u003c/div\u003e\n);\n\n// navigation.tsx\nimport { reverseUrl } from 'typed-route';\nimport { routes } from './constants/routes';\n\nconst Navigation = () =\u003e (\n  \u003cdiv\u003e\n      \u003cLink to={reverseUrl(routes.item, { id: 1 })}\u003eLink to item\u003c/Link\u003e\n      \u003cLink to={reverseUrl(routes.form.subForm, { id: 2, sub: 'test' })}\u003eLink to sub form\u003c/Link\u003e\n      {/* TS Error: Property 'id' is missing */}\n      \u003cLink to={reverseUrl(routes.form.subForm, { sub: 'test' })}\u003eError link\u003c/Link\u003e\n  \u003c/div\u003e\n);\n\n```\n\n## Quick Start\n### Requirements\n- npm or Yarn\n- Node.js 10.0.0 or higher\n- Typescript 3.5.0 or higher\n\n\n### Installation\n```bash\n$ npm install typed-route\n```\n\nIf you are using Yarn, use the following command.\n\n```bash\n$ yarn add typed-route\n```\n\n## Usage\n\n### typedRoute\n`typedRoute` - generic function creates string with saved context\n\n`typedRoute\u003c'name'\u003e('/:name')` - creates a string route with one param `{ name: string }`\n\n`typedRoute\u003c'id' | 'name'\u003e('/:id/:name')` - creates a string route with a few params `{ id: string, name: string }`\n\n`typedRoute\u003c'id', 'name'\u003e('/:id/:name?')` - you can add optional params `{ id: string, name?: string }`\n\n### routeMap\nCreates a route map merging all routes string and contexts\n\n```ts\nlet routes;\nroutes = routeMap('/base', {\n  page1: '/page1',\n  page2: routeMap('/page2', {\n    info: '/info',\n    form: '/form'\n  })\n});\nconsole.log(routes);\n/* {\n  index: '/base',\n  page1: '/base/page1',\n  page2: {\n    index: '/base/page2',\n    info: '/base/page2/info',\n    form: '/base/page2/form'\n  }\n} */\n\n```\n\n### reverseUrl\nType safe function generates an url using typed route and route params\n```ts\nreverseUrl(\n  typedRoute('/item'),\n); // item\n\nreverseUrl(\n  typedRoute\u003c'id'\u003e('/item/:id'),\n  { id: 1 }\n); // item/1\n\nreverseUrl(\n  typedRoute\u003c'id'\u003e('/item/:id'),\n); // TS Error\n\nreverseUrl(\n  typedRoute\u003c'id'\u003e('/item/:id'),\n  {}\n); // TS Error: Property 'id' is missing\n\nreverseUrl(\n  typedRoute\u003c'id' | 'optional'\u003e('/item/:id/:second'),\n  { id: 1, second: 2 }\n); // item/1/2\n\nreverseUrl(\n  typedRoute\u003c'id', 'optional'\u003e('/item/:id/:optional?'),\n  { id: 1 }\n); // item/1\n\nreverseUrl(\n  typedRoute\u003c'id', 'optional'\u003e('/item/:id/:optional?'),\n  { id: 1, optional: 'test' }\n); // item/1/test\n```\n\n### InferTypedRoute\nInfer params from types route\n```ts\nlet route = typedRoute\u003c'id'\u003e('/item/:id');\ntype I1 = InferTypedRoute\u003ctypeof route\u003e;\n// { id: string }\n\nroute = typedRoute\u003c'id' | 'second'\u003e('/item/:id/:second');\ntype I2 = InferTypedRoute\u003ctypeof route\u003e;\n// { id: string; second: string }\n\nroute = typedRoute\u003c'id', 'optional'\u003e('/item/:id/:optional?');\ntype I3 = InferTypedRoute\u003ctypeof route\u003e;\n// { id: string; optional?: string }\n\nconst routes = {\n  list: '/list',\n  form: routeMap(typedRoute\u003c'id'\u003e('/form/:id'), {\n    subForm: routeMap(typedRoute\u003c'sub'\u003e('/:sub'), {\n      detail: '/detail',\n    })\n  })\n};\ntype I5 = InferTypedRoute\u003ctypeof routes.form.subForm.detail\u003e;\n// { id: string; sub: string }\n```\nYou can use it with react-router\n```tsx\ntype SubFormProps = RouteComponentProps\u003cInferTypedRoute\u003ctypeof routes.form.subForm.detail\u003e\u003e;\n\nconst SubFormPage: React.FC\u003cSubFormProps\u003e = ({ match }) =\u003e (\n  \u003cdiv\u003e\n    Subform params:\n    { match.params.id }\n    { match.params.sub }\n  \u003c/div\u003e\n);\n``` \n\n### InferRouteMap\nGenerates route map type params\n```ts\nconst routes = {\n  list: '/list',\n  form: routeMap(typedRoute\u003c'id'\u003e('/form/:id'), {\n    info: '/info',\n    subForm: routeMap(typedRoute\u003c'sub'\u003e('/:sub'), {\n      detail: '/detail',\n    })\n  })\n};\ntype RoutesParams = InferRouteMap\u003ctypeof routes\u003e;\n/* {\n list: object;\n form: {\n   index: { id: string };\n   info: { id: string };\n   subForm: {\n     index: { id: string };\n     detail: { id: string; sub: string }\n   }\n }\n*/\n```\nAnd you can use it with react-router instead of InferTypedRoute\n```tsx\ntype SubFormProps = RouteComponentProps\u003cRoutesParams['form']['subForm']['detail']\u003e;\n\nconst SubFormPage: React.FC\u003cSubFormProps\u003e = ({ match }) =\u003e (\n  \u003cdiv\u003e\n    Subform params:\n    { match.params.id }\n    { match.params.sub }\n  \u003c/div\u003e\n);\n``` ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatrue%2Ftyped-route","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatrue%2Ftyped-route","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatrue%2Ftyped-route/lists"}