Vue-router报错Argument of type ... is not assignable to parameter of type 'RouterOptions'的解决方案

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/HermitSun/article/details/99683861

这个问题说起来也奇怪,之前一直用得好好的,打包的时候突然router就报错了。报错信息很长,其中最主要的就是这一段:

  Argument of type '{...(中间一大段代码略过)}' is not assignable to parameter of type 'RouterOptions'.
  Types of property 'routes' are incompatible.

这种报错一看就是TS的类型异常。修复这个bug也很容易,只需要进行一次类型转换就好了:

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
} as RouterOptions);

但是为什么呢?


(大段源码预警)

仔细分析一下,发现是升级vue-function-api到2.2.0之后出现了这个问题。2.2.0里对setup的返回值进行了修改,我们可以看看它的类型:

export declare function createComponent<PropsOptions, RawBindings>(options: ComponentOptions<PropsOptions, RawBindings>): VueProxy<PropsOptions, RawBindings>;

import { VueConstructor, VNode, ComponentOptions as Vue2ComponentOptions } from 'vue';

declare type VueProxy<PropsOptions, RawBindings> = Vue2ComponentOptions<never, UnwrapValue<RawBindings>, never, never, PropsOptions, ExtractPropTypes<PropsOptions, false>> & VueConstructorProxy<PropsOptions, RawBindings>;

declare type VueConstructorProxy<PropsOptions, RawBindings> = {
    new (): ComponentRenderProxy<ExtractPropTypes<PropsOptions>, UnwrapValue<RawBindings>, ExtractPropTypes<PropsOptions, false>>;
};

declare type ComponentRenderProxy<P = {}, S = {}, PublicProps = P> = {
    $data: S;
    $props: PublicProps;
    $attrs: Data;
    $refs: Data;
    $slots: Data;
    $root: ComponentInstance | null;
    $parent: ComponentInstance | null;
    $emit: (event: string, ...args: unknown[]) => void;
} & P & S;

从代码里可以看到,这里的返回值类似于一个多继承。也就是说,使用vue-function-api后,返回值变成了Vue2.x和3.x的混合体。而我们再看看router对类型的要求:

export interface RouteConfig {
  path: string;
  name?: string;
  component?: Component;
  components?: Dictionary<Component>;
  redirect?: RedirectOption;
  alias?: string | string[];
  children?: RouteConfig[];
  meta?: any;
  beforeEnter?: NavigationGuard;
  props?: boolean | Object | RoutePropsFunction;
  caseSensitive?: boolean;
  pathToRegexpOptions?: PathToRegexpOptions;
}

type Component = ComponentOptions<Vue> | typeof Vue | AsyncComponent;

export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
  = AsyncComponentPromise<Data, Methods, Computed, Props>
  | AsyncComponentFactory<Data, Methods, Computed, Props>

export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
  resolve: (component: Component<Data, Methods, Computed, Props>) => void,
  reject: (reason?: any) => void
) => Promise<Component | EsModuleComponent> | void;

export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
  component: AsyncComponentPromise<Data, Methods, Computed, Props>;
  loading?: Component | EsModuleComponent;
  error?: Component | EsModuleComponent;
  delay?: number;
  timeout?: number;
}

简而言之,无论是直接导入,还是通过()=>import('foo.vue')的方式异步加载,这里需要的都是一个Vue2.x里的component。回忆一下在C++里是怎么处理多继承的问题的?强制类型转换来明确类型。所以,vue-function-api带来的交叉类型需要强制类型转换来进行明确;这也就是问题的来源了。

猜你喜欢

转载自blog.csdn.net/HermitSun/article/details/99683861
今日推荐