2.5.17
https://codesandbox.io/s/8z04jxj3y8
I can pass any component to Vue.component
Type error:
Argument of type 'Component<DefaultData<never>, DefaultMethods<never>, DefaultComputed, Record<string, any>>' is not assignable to parameter of type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Rec...'.
Type 'VueConstructor<Vue>' is not assignable to type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Rec...'.
Value of type 'VueConstructor<Vue>' has no properties in common with type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Rec...'. Did you mean to call it?
Adding the following overload to Vue.component will fix it:
component<Data, Methods, Computed, Props>(
id: string,
definition: Component<Data, Methods, Computed, Props>,
): ExtendedVue<V, Data, Methods, Computed, Props>;
This is because Component type is a union type with VueConstructor and ComponentOptions.
Why do you use Component type? It means your getComponent function can return both Vue constructor and component options object.
I think you should use more concrete type such as VueConstructor or ComponentOptions as the return type.
Because the function loads components via webpacks require.context. Also there is a EsModule type for async comps that hints against Component. There is also a Vue.component overload foreach member type of the Component union. I think that is just a problem of typescript not being able to check that correctly.
Another indicator for this being a ts problem is that the following works:
const comp: Component = {};
Vue.component('test', comp);
well, {} is a valid component
ofc it is. that is not the point. but then TS somehow finds the correct Vue.component overload:
// type Component = typeof Vue | ComponentOptions | FunctionalComponentOptions;
const first = {};
const firstComponent: Component = first;
Vue.component('first', first); // ok
Vue.component('firstComponent', firstComponent); // ok
const second = { functional: true };
const secondComponent: Component = second;
Vue.component('second', second); // ok
Vue.component('secondComponent', secondComponent); // ok
const third = Vue.extend({});
const thirdComponent: Component = third;
Vue.component('thrid', third); // ok
Vue.component('thirdComponent', thirdComponent); // ok
declare function getComponent(): Component;
const final: Component = getComponent();
Vue.component('final', final); // type error
It is a typescript problem. TS seems like it doesnt allow multiple overloads to match (what the final case is requiring).
here is a plain typescript example demonstrating the problem:
interface A {
a: string;
}
interface B {
b: string;
}
interface C {
c: string;
}
type union = A | B | C;
declare function acceptsUnion(x: A): void;
declare function acceptsUnion(x: B): void;
declare function acceptsUnion(x: C): void;
declare function returnsUnion(): union;
acceptsUnion(returnsUnion()); // type error
I see your use case. I'm not sure that union type sometimes passes overload but we can replace fallback overload of component method with Component type.
any update on this?
i am using the following vue.d.ts in my projects, which solves the type problem according to @ktsn proposed solution:
import Vue, { Component } from 'vue';
import { ExtendedVue } from 'vue/types/vue';
declare module 'vue/types/vue' {
interface VueConstructor<V extends Vue = Vue> {
component<Data, Methods, Computed, Props>(
id: string,
definition: Component<Data, Methods, Computed, Props>,
): ExtendedVue<V, Data, Methods, Computed, Props>;
}
}
Most helpful comment
any update on this?
i am using the following
vue.d.tsin my projects, which solves the type problem according to @ktsn proposed solution: