问题
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