-
-
Notifications
You must be signed in to change notification settings - Fork 489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support typed routes inside localePath() #2813
Comments
As workaround, I added this snippet inside d.ts file and it works: /// <reference types="unplugin-vue-router/client" />
import type { RouteLocation, RouteLocationNormalizedLoaded, RouteLocationRaw, Router } from '#vue-router';
declare module '#i18n' {
export type StubbedLocalePathFunction = (route: RouteLocation | RouteLocationRaw, locale?: Locale) => string;
export declare function useLocalePath(): StubbedLocalePathFunction;
} |
Thanks @AndreyYolkin! I modified it a bit, because lately
export const locales = [
'nl',
'en',
'fr',
'de',
] as const;
export type AppLocale = typeof locales[number];
import type { RouteNamedMap } from 'vue-router/auto-routes';
import type { RouteLocation, RouteLocationRaw } from 'vue-router';
type RouteName = keyof RouteNamedMap;
type WithoutLocale<T extends string> = T extends `${infer Base}___${AppLocale}` ? Base : T;
type OriginalRouteDefinition<T extends RouteBaseName> = RouteNamedMap[`${T}___${AppLocale}`];
type ReplaceParamsInPath<
Path extends string,
Params extends Record = Record<PropertyKey, never>,
> = Params extends Record<PropertyKey, never>
? Path
: Path extends `${infer Before}:${infer Param}()${infer Rest}`
? ReplaceParamsInPath<`${Before}${Params[Param]}${Rest}`, Omit<Params, Param>>
: Path;
declare global {
type RouteBaseName = WithoutLocale<RouteName>;
}
declare module '#i18n' {
// This makes sure `useLocalePath` uses the typed router, but with every
// route's base name, instead of the `___{locale}` suffixed one.
type StubbedUseLocalePathFunction = <
RouteName,
Locale extends AppLocale = AppLocale,
RouteDefinition = OriginalRouteDefinition<RouteName, Locale>,
const Params = RouteDefinition['params'],
>(
route: RouteName extends RouteBaseName
? (RouteName | {
name: RouteName;
params?: RouteDefinition['params'];
})
: (RouteLocation | RouteLocationRaw),
locale?: Locale
) => RouteName extends RouteBaseName
? ReplaceParamsInPath<RouteDefinition['path'], Params>
: string;
export function useLocalePath (): StubbedLocalePathFunction;
} It would indeed be very useful to have this built in, so no stubs are needed. It seems to me however, that this might become quite complicated, as |
A collaborative route would be the best, with the current state of Nuxt and Vue Router we would need to reimplement type generation and rely on internal types, which could be changed at any time. I do have a branch that has these types generated, I might implement it at some point under an experimental flag but with no promise that it will keep on working, you can check it out here BobbieGoede#49.
In v9 we've added a generated |
Oh that's nice, I see you're way ahead of me! Looking forward to it! 😄 |
Here's a demo using a preview build (the types only work in the typescript files cause of stackblitz): https://stackblitz.com/edit/bobbiegoede-nuxt-i18n-starter-srohiz?file=nuxt.config.ts&file=composables%2Ftest.ts There's other stuff not quite working yet, you can track its progress in #3142 and chime in with any feedback! |
Nice start! Shouldn't const test = localePath({
name: 'test-slug',
// params: {}
}); |
@Anoesj |
Hmm yeah, it does result in a runtime error though. That's not very nice. People use TypeScript to prevent runtime errors. I wouldn't mind |
Oh I wasn't even aware it threw a runtime error (too focused on the types right now 😅) I would expect there already being an issue open about this 🤔 I can open one if there isn't one (or if you would like to do so feel free and link back here). |
EDIT: There already seems to be an issue for this: posva/unplugin-vue-router#285 |
Ah, it's actually not always wrong to omit
In the component that renders <RouterLink :to="{ name: 'user-id-settings' }">
⚙️ {{ $route.params.id }}'s settings
</RouterLink> Here, we can omit the params without causing a runtime error, as In fact, it doesn't look at the hierarchy of the routes, it just looks for params in the current route with the same name as params in the target route and automatically fall back on the current route's param values. See posva/unplugin-vue-router#285:
|
I have just published the first release candidate for v9 which includes the experimental typed routes Try it out and please open new issues if you experience any with this feature 🙏 |
Describe the feature
According to the code here, nuxt i18n imports types from
vue-router
package:i18n/src/runtime/composables/index.ts
Line 24 in c43842f
However, nuxt itself registers
#vue-router
alias to handle both situations with enabled/disabled typed routes. Example of usage: https://github.com/nuxt/nuxt/blob/d326e054d372bd2eb5bf75f3feca6a291169ff76/packages/nuxt/src/pages/runtime/utils.ts#L2Since nuxt/i18n is a nuxt module, I suppose we can rely on this alias too and enable type imports by replacing
vue-router
with#vue-router
for types importsAdditional information
Final checks
The text was updated successfully, but these errors were encountered: