Subscribe on changes!

script setup: expected TypeScript type by compiler for defineEmit is not useful

avatar
Dec 24th 2020

Version

3.0.4

Reproduction link

TypeScript Playground

Steps to reproduce

const emit = defineEmit<SOME_TYPE_HERE>();
emit('foo');
emit('bar');
emit('baz', 1);

What is expected?

Should be able to specify SOME_TYPE_HERE correctly so the resulting program has no TypeScript error and no error from vue compiler.

What is actually happening?

  • SOME_TYPE_HERE = ((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void) => TypeScript error
  • SOME_TYPE_HERE = {(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;} => vue compiler error
[@vue/compiler-sfc] type argument passed to defineEmit() must be a function type or a union of function types.

https://github.com/vuejs/vue-next/blob/085bbd5fe07c52056e9f7151fbaed8f6a2e442b3/packages/compiler-sfc/__tests__/compileScript.spec.ts#L522

Currently the type expected for defineEmit is a function type or union type, but the type ((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void) is actually not useful as a emit function, as can be seen in the above TypeScript playground, since the type ((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void) is equivalent to ((e: never, id: number) => void).

The correct way to specifies this seems to be using call signature {(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;}.

avatar
Dec 24th 2020

((e: 'foo' | 'bar') => void) & ((e: 'baz', id: number) => void) also works for TypeScript, but vue compiler reject this too.

avatar
Mar 12th 2021

With an interface I also gen a compiler Error:

interface Emit {
  (e: 'delete', id: string): void;
  (e: 'duplicate', id: string): void;
  (e: 'start', id: string): void;
}
const emit = defineEmit<Emit>();
Syntax Error: TypeError: Cannot read property 'content' of null

Bildschirmfoto 2021-03-12 um 09 00 31

But the types ware correct. Any solutions to this? :)