Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue.component doesnt except argument of type Component #8719

Open
backbone87 opened this issue Aug 28, 2018 · 8 comments
Open

Vue.component doesnt except argument of type Component #8719

backbone87 opened this issue Aug 28, 2018 · 8 comments

Comments

@backbone87
Copy link

Version

2.5.17

Reproduction link

https://codesandbox.io/s/8z04jxj3y8

Steps to reproduce

  • Click repro link
  • Open test.ts
  • See type errors
  • Uncomment vue type augmentation to see errors disappear

What is expected?

I can pass any component to Vue.component

What is actually happening?

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>;
@ktsn
Copy link
Member

ktsn commented Aug 28, 2018

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.

@backbone87
Copy link
Author

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.

@backbone87
Copy link
Author

Another indicator for this being a ts problem is that the following works:

const comp: Component = {};
Vue.component('test', comp);

@posva
Copy link
Member

posva commented Aug 28, 2018

well, {} is a valid component

@backbone87
Copy link
Author

backbone87 commented Aug 28, 2018

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).

@backbone87
Copy link
Author

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

@ktsn
Copy link
Member

ktsn commented Aug 29, 2018

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.

@backbone87
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants