victorgarciaesgi/nuxt-typed-router

$route.params or $typedRoute.params unknown type is problematic

Closed this issue · 6 comments

Describe the bug
I'm trying to do the following with a nested dynamic route like /:username/:profileId:

<NuxtLink :to={ name: $routeNames.profile, params: $typedRoute.params  }>
   ....
</NuxtLink

But $typedRoute.params's default type is unknown. params then complains with:

Type 'unknown' is not assignable to type '{ username: string | number; profileId: string | number; }'.

Expected behavior
It would be nice if the type inferred based on the name I gave (like how the params already does that). At a minimum, it would be nice if it was any so I could pass it without having to coalesce the type.

Screenshots
N/A

Environnement infos

- Operating System: Windows_NT
- Node Version:     v18.12.1
- Nuxt Version:     3.8.1
- CLI Version:      3.9.1
- Nitro Version:    2.7.2
- Package Manager:  pnpm@8.9.0
- Builder:          -
- User Config:      devtools, modules, imports, vue, routeRules, css, googleFonts, sourcemap, nitro
- Runtime Modules:  @pinia/nuxt@0.5.1, nuxt-typed-router@3.3.3, @vueuse/nuxt@10.6.0, @unocss/nuxt@0.57.3, radix-vue/nuxt, nuxt-icon@0.6.5, @nuxtjs/google-fonts@3.0.2, @nuxt/image@1.0.0
- Build Modules:    -

Your pages folder structure

Run npx tree-node-cli {your page folder path}

pages
└── profiles
    ├── [username]
    │   └── [profileId]
    │       ├── index.vue
    ├── index.vue

Your nuxt.config.ts

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
	devtools: {
		enabled: true,
		timeline: {
			enabled: true,
		},
	},
	modules: [
		["@pinia/nuxt", { autoImports: ["defineStore"] }],
		["nuxt-typed-router", { plugin: true }],
		"@vueuse/nuxt",
		"@unocss/nuxt",
		"radix-vue/nuxt",
		"nuxt-icon",
		"@nuxtjs/google-fonts",
		"@nuxt/image",
	],
	imports: {
		dirs: ["providers"],
	},
	vue: {
		defineModel: true,
	},
	css: ["@unocss/reset/tailwind.css"],
	googleFonts: {
		families: {
			Roboto: true,
		},
	},
	sourcemap: false,
	nitro: {
		preset: "cloudflare-pages",
	},
});

Yeah it's normal that's it's unknown, $typedRoute and typescript can't know which route you're at unless you do if ($typedRoute.name === "xxxx") before.
Solution would be to use useRoute like this.

const {params} = useRoute('xxxxx')
//             ^ typed

What do you think about at least making it any instead of unknown? That way it can at least be passed.

The whole point of this module is to be typesafe, you can just use $route if you want any

Unfortunately I get this warning:

Type 'RouteParams' is not assignable to type '{ username: string | number; profileId: string | number; }'.ts(2322)

with

:to="{ name: $routesNames.siegeUsernameProfileId, params: $route.params }" 

Then if you don't want type safety you can just add $route.params as any

@victorgarciaesgi

Yeah it's normal that's it's unknown, $typedRoute and typescript can't know which route you're at unless you do if ($typedRoute.name === "xxxx") before. Solution would be to use useRoute like this.

const {params} = useRoute('xxxxx')
//             ^ typed

is doing the following inside the page products/[slug].vue without the the if check safe?

const route = useRoute('products-slug')

if it is, would there be a build-time way to figure out in which pages/.. useRoute is used and based on that automatically infer the route name?

I understand how this is impossible to determine at built time within other components but route components should work