Typed routes
A @link component whose href autocompletes from your site's real routes.
TypeScript autocompletes string-literal unions inside quotes. Declare your routes as one, reference it from a component’s @types, and every @link call site gets route autocomplete and dead-link squiggles — with zero new tooling.
Declare the routes as a union
// Generated by a script, or hand-written to start.
export type AppRoute = '/' | '/profile' | '/settings' | '/posts'Hand-write it in five minutes, or generate it — from AdonisJS (node ace list:routes --json), a file-based pages directory, or wherever your routes live. It’s one type alias; any script that can list your routes can emit it.
Reference it from the component
{{--
@name Link
@desc Site-internal anchor; href is checked against the route manifest.
@types {
to: import('#gen/routes').AppRoute
label: string
}
--}}
<a href="{{ to }}">{{ label }}</a>Every call site is now checked
@link({ to: '/profil', label: 'Profile' })
@end'/profil' gets a red squiggle — Type ‘“/profil”’ is not assignable to type ‘AppRoute’ — in the editor and from edge-check in CI. Put the cursor inside the quotes and the editor offers '/', '/profile', '/settings', '/posts'.
Delete a route from the union and every template still linking to it errors. Dead links become a compile error.
The fancy version: dynamic segments
Template-literal types make parameterized routes checkable too:
export type AppRoute = '/' | '/profile' | `/users/${string}` | `/posts/${number}`
@link({ to: '/users/42' }) passes; @link({ to: '/user/42' }) fails. With a router that exposes route names and params (AdonisJS does), a generator could go further and emit a typed route() helper signature.