Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare TypeScript type interface for custom meta fields in Vue Router v4?

With Vue Router version 4, which is currently in beta.11 in vue-router-next repo, there is a documentation page about how to define meta fields custom type interface with TypeScript.

declare module 'vue-router' {
  interface RouteMeta {
    // is optional
    isAdmin?: boolean
    // must be declared by every route
    requiresAuth: boolean
  }
}

To be placed along the Vue shim module declaration. Mine is looking like:

declare module '*.vue' {
  import { defineComponent } from 'vue';

  const component: ReturnType<typeof defineComponent>;
  export default component;
}

declare module 'vue-router' {
  interface RouteMeta {
    isPublic?: boolean;
  }
}

However, this is not working. Instead this way of defining the interface seems to overwrite the interface that is shipped with the package, or rather declaring 'vue-router' module seems to do that.

What would be the correct way of defining custom meta field types?

like image 235
ux.engineer Avatar asked Sep 21 '20 19:09

ux.engineer


People also ask

Does vue2 support TypeScript?

Vue 2 already has good support for TypeScript, and the recently published Vue 2.7 backported a lot of useful features from Vue 3, like composition API, <script setup> , and defineComponent , further improving the developer experience of TypeScript in Vue.

What is meta in route vue?

Sometimes, you might want to attach arbitrary information to routes like transition names, who can access the route, etc. This can be achieved through the meta property which accepts an object of properties and can be accessed on the route location and navigation guards.


1 Answers

Their documentation is wrong or at best incomplete.

A Module Augmentation uses the same syntax as an Ambient Module declaration and is only considered an augmentation when it is within a module file itself. A module is defined, as per the ECMAScript specification, as a file containing one or more top level import or export statements.

The snippet in a file that is not a module does exactly what you've noticed. It supplants any other types for the 'vue-router' package instead of augmenting them. But we want to augment that package's types, not replace them.

However, a declare module statement that is intended as a declaration, not an augmentation, must be in a file that is, conversely, not a module. That is, in a file not containing any top level import or export statements.

To resolve this, move the declare module 'vue-router' {...} to a separate file (say, augmentations.d.ts), and make that file a module by beginning it with export {}.

// augmenations.d.ts

// Ensure this file is parsed as a module regardless of dependencies.
export {}

declare module 'vue-router' {
  interface RouteMeta {
    // is optional
    isAdmin?: boolean
    // must be declared by every route
    requiresAuth: boolean
  }
}

Now let's come back and take look at the original code in question.

// shims-vue.d.ts

declare module '*.vue' {
  import { defineComponent } from 'vue';

  const component: ReturnType<typeof defineComponent>;
  export default component;
}

declare module 'vue-router' {
  interface RouteMeta {
    isPublic?: boolean;
  }
}

The two declare module statements cannot exist in the same file because one of them is trying to declare a module, '*.vue', and the other to augment one. Therefore, we will leave the declare module '*.vue' {...} where it is, as it is functioning as intended.

like image 127
Aluan Haddad Avatar answered Oct 12 '22 16:10

Aluan Haddad