Subscribe on changes!

EmitsOptions has different shape requirements on FunctionalComponent<P, E> VS script setup's defineEmits<E>()

avatar
Jul 19th 2021

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 }
avatar
Jul 20th 2021

They are different by design:

  • The E argument of FunctionalComponent is the shape of the runtime emits option. i.e. the type should match what you would write as the value of the emits option:

    emits: {
       eventName: (payload: string) => { /* validation logic */ }
    }
    
  • The argument of defineEmits is the shape of the emit call. That's why it's an interface with callable signatures:

    emit('eventName', payload)
    
avatar
Jul 20th 2021

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?