vuejs / router

🚦 The official router for Vue.js
https://router.vuejs.org/
MIT License
3.74k stars 1.15k forks source link

RouteMeta is should be Partial in RouteRecordNormalized #2285

Closed OldStarchy closed 1 week ago

OldStarchy commented 1 week ago

Reproduction

Define required fields on RouteMeta, but omit meta from routes.

Steps to reproduce the bug

router.ts

import { createRouter, createWebHistory } from 'vue-router';

declare module 'vue-router' {
  interface RouteMeta {
    title: string;
  }
}

const router = createRouter({
  history: createWebHistory(),
  routes: [{
    path: '/foo',
    component: () => import('@/foo.vue'),
  }]
});

App.vue

import { useRoute } from 'vue-router';

const route = useRoute();

const metaTitle = computed(
  () => route.meta.title,
);

Expected behavior

Either

  1. metaTitle should be recognized as string | undefined.
  2. route.meta should be typed as RouteMeta | undefined (and be undefined when there is no meta defined for the route)

Actual behavior

route.meta is an empty object that does not conform to the RouteMeta interface.

metaTitle is recognized as string, despite being undefined.

Additional information

RouteRecordRaw's meta property is optional. However the route returned by useRoute always contains a meta object and in this case is empty.

useRoute() returns a RouteLocationNormalizedLoaded which inherits meta: RouteMeta from MatcherLocation. This should be marked as meta: Partial<RouteMeta>.

useRouter().getRoutes() returns a RouteRecordNormalized[] which defines meta: Exclude<_RouteRecordBase['meta'], void>. This shouldb e defined as meta: Partial<Exclude<_RouteRecordBase['meta'], void>>

The fact that route.meta is always defined even for routes that don't have a defined meta object is likely an artifact due to the way meta data is inherited by nested routes, so I understand if it ends up being too difficult to set that field to undefined if the route (and its parents) didn't have any meta defined.

Making the meta property in _RouteRecordBase required would allow us to require meta data to be present when defining routes, but may be annoying for those that don't need metadata, but this would be the most type-safe way of enforcing metadata, though would require behavioral changes.

Marking the above mentioned properties as Partial is the correct way to type the current behavior that is "We know you've made these RouteMeta properties required, but that doesn't mean they'll be on this route".

posva commented 1 week ago

To answer your points:

This is tracked but it will have to wait a major due to being a breaking change

OldStarchy commented 4 days ago

Thanks for your reply. I'll look forward to the next version.