EmitsOptions has different shape requirements on FunctionalComponent<P, E> VS script setup's defineEmits<E>()
What problem does this feature solve?
If the E in FunctionalComponent<P, E>
is EmitsOptions, and the E in defineEmits<E>()
is EmitsOption, why do they have different shapes?
E in FunctionalComponent<P, E> has to be { "event-name": (param: Param) => void }
E in defineEmits<E>() has to be { (event: "event-name", param: Param): void }
What does the proposed API look like?
{ "event-name": (param: Param) => void }
They are different by design:
The
E
argument ofFunctionalComponent
is the shape of the runtimeemits
option. i.e. the type should match what you would write as the value of theemits
option:emits: { eventName: (payload: string) => { /* validation logic */ } }
The argument of
defineEmits
is the shape of theemit
call. That's why it's an interface with callable signatures:emit('eventName', payload)
A thing that I just notice, defineEmits
's argument is a callable with a void return, and even if you change it to a number or string, the way that you would use emit is still treating it as a void return function. Why isn't tuple considered for typing emit's parameters instead of a callable type? The purpose of this type argument is really just to type check the params you pass to the emit function right? I think it would be confusing to have people define a callable type but they would never have to actually implement a function against that type, and only the param types of this callable type are actually meaningful.
If the return type is always void, wouldn't it be better to use a shape that specifies only the essential type info?