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

本秂侑毒 提交于 2021-01-27 16:44:08

问题


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?


回答1:


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 an 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.



来源:https://stackoverflow.com/questions/63999118/how-to-declare-typescript-type-interface-for-custom-meta-fields-in-vue-router-v4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!