Search code examples
typescriptvue.jsvue-clivuejs3

Vue 3 + Typescript emit function "No overload matches this call" even if the function name is defined. It looks like order matters


I found a weird error message in Vue 3 emit function when i use it with TypeScript. example code to reproduce:

export default defineComponent({
  emits: {
    emit1: (payload: number) => payload,
    emit2: (payload: string) => payload
  },
  methods: {
   ...
  }
}

when i try to call the emit1 like the following, it compiles without an error: this.$emit("emit1", 1);

but if i do the following there is weird error: this.$emit("emit1", "test");

TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '"emit1"' is not assignable to parameter of type '"emit2"'.

if i change the order of the emit functions like so:

export default defineComponent({
  emits: {
    emit2: (payload: string) => payload,
    emit1: (payload: number) => payload
  },
  methods: {
   ...
  }
}

Of course also a error appears, but this one make more sense at least:

TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type 'boolean' is not assignable to parameter of type 'number'.

since the function name is defined in both cases the error message #1 makes no sense but #2 does.

My Questions:

  • why does the order of the functions has an impact on the error message?
  • should / can this be fixed in vue so that the error makes sense in both cases? Mybe this is also a issue with TypeScript itself?

Solution

  • When using the latest Vue CLI version, here is the full error received with either emit order. When switching the order of the emits, it still shows both error messages, just in reverse order:

    TS2769: No overload matches this call.
      Overload 1 of 2, '(event: "emit1", payload: number): void', gave the following error.
        Argument of type '"test"' is not assignable to parameter of type 'number'.
    
      Overload 2 of 2, '(event: "emit2", payload: string): void', gave the following error.
        Argument of type '"emit1"' is not assignable to parameter of type '"emit2"'. 
    

    This makes it quite clear what's happening, though since you could only see one of the messages it was very confusing:

    • Vue is testing the emit against all potentially matching emits entries (i.e. the overloads). Both the emit name you use in the method and the emit value are provided as parameters to the testing function. That's where you see event, payload passed as arguments.

    • With one overload, the event parameter has a match but the value parameter causes a type error. With the other, there is no event match.