Links
Build links from a definition. The query leaves defaults out, and the path is checked against the route table.
On this page
href and search
listState.href('/products');
// '/products'
listState.href('/products', { inStock: true, page: 2 });
// '/products?inStock=true&page=2'
listState.search({ page: 2 });
// 'page=2'href(path, values?) builds a link from the definition. A field you leave out means its default, and a field at its default is left out of the query. The shape of the URL it builds is described on URL.
search(values?) returns the query string alone, without the ?. Use it when you put the path together yourself, such as giving a download URL the same filters as the list.
The return type keeps the path you passed as a literal, so a typed-route check on the receiving side, such as Next.js’s <Link>, can strip the query and verify the path. For an entry-only definition, href returns the link with no query and search an empty string. A value no URL can represent makes both throw an error containing has no URL serialization.
Vite’s base
listState.href('/products', { page: 2 });
// '/docs/products?page=2'The path href takes is written without the base, as the patterns of the route table are. The link it returns has Vite’s base in front: under base: '/docs/', it is '/docs/products?page=2'.
Do not pass it a link that href of @k8ordo/router returned, since that link already carries the base.
Outside Vite, in Next.js for example, there is no import.meta.env, so nothing is prepended. That framework’s own <Link> adds its basePath.
Typed paths
src/k8ordo.d.tsimport type { routes } from './routes';
declare module '@k8ordo/router' {
interface Register {
routes: typeof routes;
}
}
declare module '@k8ordo/state' {
interface Register {
routes: typeof routes;
}
}Augment Register once, and every href in the application turns a path the route table lacks into a type error. The line routes: typeof routes is the same as in the @k8ordo/router augmentation, described in Typed paths. Under @k8ordo/framework this declaration is generated from src/routes/ into .k8ordo/register.gen.ts, so do not write it yourself. It is generated when the application’s own package.json lists @k8ordo/state in dependencies or devDependencies. A dependency through another package does not count.
The path is matched against the patterns of the table segment by segment. A fixed segment must be spelled as the pattern spells it. A :param segment takes any one non-empty segment, a ${string} from a template literal included. A pattern with a * cannot be linked to. A path no pattern matches is a type error, so even a table starting with /:locale refuses '/ja/nowhere'.
The check uses NavigablePath from @k8ordo/router as a type only. The router stays an optional peer and never loads at runtime.
types/k8ordo.d.tsimport type { Route } from 'next';
declare module '@k8ordo/state' {
interface Register {
path: Route;
}
}A router other than @k8ordo/router has no table to hand over, so register the path union of that router under path, such as Route from next. When both routes and path are present, routes wins. With neither, any string starting with / passes.
Pitfall
Augment Register only in an application. A shared library that augments it imposes the constraint on every consumer.