UNPKG

cl-fill-link

Version:

Fill generated nextjs links with dynamic values

142 lines (106 loc) 4.08 kB
## Fill dynamic nextjs links ###### Note This program is intended to be used with [generate-next-links](https://github.com/Lindeneg/generate-next-links) but it can be used with any input that follows nextjs [dynamic routes](https://nextjs.org/docs/routing/dynamic-routes). It also offers a type-safe implementation. ## Install `yarn add cl-fill-link` --- ## Usage ```ts import { fillLink } from 'cl-fill-link'; enum AppLink { CUSTOMERID_SETTINGS_VIEW = '/[customerId]/settings/[view]', BLOG_OPTIONAL_CATCHALL_SLUG = '/blog/[[...slug]]', } // returns: '/some-id/settings/templates' fillLink(AppLink.CUSTOMERID_SETTINGS_VIEW, { customerId: 'some-id', view: 'templates', }); // returns: '/blog/category/music/jazz/miles-davis' fillLink(AppLink.BLOG_OPTIONAL_CATCHALL_SLUG, { slug: ['category', 'music', 'jazz', 'miles-davis'], }); ``` ## Type safety If a key is missing, has an inappropriate type or does not exist, TypeScript will complain ```ts // TypeScript Error: // Property 'customerId' is missing in type '{ view: string; }' // but required in type '{ customerId: PrimitiveTypeConstraint; }' fillLink('/[customerId]/settings/[view]', { view: 'templates', }); // TypeScript Error: // Object literal may only specify known properties, // but 'view2' does not exist in type fillLink('/[customerId]/settings/[view]', { view2: 'templates', customerId: 1, }); // TypeScript Error: // Type 'string[]' is not assignable to // type 'PrimitiveTypeConstraint'. fillLink('/[customerId]/settings/[view]', { view: ['templates'], customerId: 1, }); ``` The expected type for catch-all routes is always an array of strings. For optional-catch-all routes, `[[...slug]]` an empty array is accepted, as optional catch all routes includes the index of the path, while catch all routes, `[...slug]` only accepts a non-empty array. ```ts // OK fillLink('/hello/[...there]', { there: ['something'] }); // TypeScript Error: // Type 'string' is not assignable to type // '[PrimitiveTypeConstraint, ...PrimitiveTypeConstraint[]]' fillLink('/hello/[...there]', { there: 'something' }); // TypeScript Error: // Source has 0 element(s) but target requires 1 fillLink('/hello/[...there]', { there: [] }); // OK fillLink('/hello/[[...there]]', { there: [] }); // OK fillLink('/hello/[[...there]]', { there: ['something'] }); // TypeScript Error: // Type 'string' is not assignable to type 'PrimitiveTypeConstraint[]' fillLink('/hello/[[...there]]', { there: 'something' }); ``` ## Query Params Use the `$query` property to specify an object containing [query-parameters](https://en.wikipedia.org/wiki/Query_string). The `$` sign is prefixed to avoid collision with an actual `query` key in the link itself. Note that properties of the `$query` object must have values of a `primitive` type. ```ts enum AppLink { CATEGORYID_CONTENT_GENRE = '/[categoryId]/content/[genre]', } // returns: '/music/content/jazz?artist=miles-davis&tune=so-what&year=1959&autoplay=true' fillLink(AppLink.CATEGORYID_CONTENT_GENRE, { categoryId: 'music', genre: 'jazz', $query: { artist: 'miles-davis', tune: 'so-what', year: 1959, autoplay: true, }, }); ``` The parameters are each encoded into valid `URI` components and thus you can safely do stuff like this ```ts enum AppLink { CATEGORYID_CONTENT_GENRE = '/[categoryId]/content/[genre]', } // returns: '/music/content/jazz?artist=miles%20davis&tune=so%20what%20%7C%20kind%20of%20blue&year=%5B1959%5D' fillLink(AppLink.CATEGORYID_CONTENT_GENRE, { categoryId: 'music', genre: 'jazz', $query: { artist: 'miles davis', tune: 'so what | kind of blue', year: '[1959]', }, }); ``` --- ## Why Nextjs natively supports the behavior this program accomplishes, as seen [here](https://nextjs.org/docs/api-reference/next/link#with-url-object). However, that is only useful within that `Link` component. Sometimes it's useful for a filled dynamic link to be constructed outside the `Link` component. This small and simple program is for exactly such a case. And then it's type-safe. ---