如何在 Vue Router v4 中为自定义元字段声明 TypeScript 类型接口?

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

使用 Vue Router 版本 4,目前 in beta.11 in vue-router-next repo, there is a documentation page 关于 如何使用 TypeScript 定义元字段自定义类型接口 .

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

沿着 Vue shim 模块声明放置。我的看起来像:

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

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

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

但是,这不起作用。相反,这种定义接口的方式似乎覆盖了包附带的接口,或者更确切地说,声明 'vue-router' 模块似乎可以做到这一点。

定义自定义元字段类型的正确方法是什么?

他们的文档是错误的,或者充其量是不完整的。

一个 Module Augmentation uses the same syntax as an Ambient Module 声明,仅当它位于模块文件本身时才被视为扩充。根据 ECMAScript 规范,模块被定义为包含一个或多个顶级 importexport 语句的文件。

非模块文件中的代码段与注意到的完全相同。它取代了 'vue-router' 包的任何其他类型,而不是增加它们。但我们想增加该包的类型,而不是替换它们。

但是,作为声明而不是扩充的 declare module 语句必须位于文件中,反之,也不是模块。也就是说,在包含任何顶级 importexport 语句的文件 not 中。

要解决此问题,请将 declare module 'vue-router' {...} 移动到一个单独的文件(例如,augmentations.d.ts),并通过以 export {}.[=25= 开头使该文件成为一个模块]

// 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
  }
}

现在回过头来看看问题的原代码

// 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;
  }
}

两个 declare module 语句不能存在于同一个文件中,因为其中一个试图声明一个模块,'*.vue',另一个试图扩充一个。因此,我们将 declare module '*.vue' {...} 保留在原处,因为它按预期运行。