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

这个问题说起来也奇怪,之前一直用得好好的,打包的时候突然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(options: ComponentOptions): VueProxy;

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

declare type VueProxy = Vue2ComponentOptions, never, never, PropsOptions, ExtractPropTypes> & VueConstructorProxy;

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

declare type ComponentRenderProxy

= { $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;
  redirect?: RedirectOption;
  alias?: string | string[];
  children?: RouteConfig[];
  meta?: any;
  beforeEnter?: NavigationGuard;
  props?: boolean | Object | RoutePropsFunction;
  caseSensitive?: boolean;
  pathToRegexpOptions?: PathToRegexpOptions;
}

type Component = ComponentOptions | typeof Vue | AsyncComponent;

export type AsyncComponent, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps>
  = AsyncComponentPromise
  | AsyncComponentFactory

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

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

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

你可能感兴趣的:(有趣的bug)