Skip to content

[TypeScript / TSX] Make component events type safe, both emitting and listening #1553

Closed
@wonderful-panda

Description

@wonderful-panda

What problem does this feature solve?

Avoid mistakes around emitting and listening component events

What does the proposed API look like?

Emitting events

// Define event type (see `About Events types` section)
type Events = {
  withoutArgs: [],
  withOneArg: [string],
  withTwoArgs: [string, number]
}

const MyComponent = defineComponent({
  props: { ... }, 
  setup(props, { emit }: SetupContext<Events>) {  // Add type parameter to SetupContext
    const emitEvents = () => {
     /*
      * OK
      */
      emit("withoutArgs");
      emit("withOneArg", "foo");
      emit("withTwoArgs", "foo", 1);

     /*
      * Compile error
      */
      emit("withoutArgs", "foo");
      emit("withOneArgs"); 
      emit("withOneArgs", "foo", 1);
      emit("withOneArgs", 1);
      emit("withTwoArgs", "foo");
      emit("wrongEventName");
    }
    ...
  }
});

Listening events

const ParentComponent = defineComponent({
  setup() {
    return () => (
      <MyComponent
        on={{
           // check event names and argument types at compile type
           withoutArgs: () => ...,
           withOneArg: arg1 => ...
        }}
      />
    )
  }
});

About Events type

There are some candidates about Events type specification.

1. specify argument types only

Pros: Compact
Cons: Argument names can't be specified

type Events = {
  event1: [],
  event2: [string],
  event3: [string, number]
}
2. specify full function signature

Pros: Meaningful argument names can be specified
Cons: Verbose

type Events = {
  event1: () => void,
  event2: (userName: string) => void,
  event3: (id: string, index: number) => void
}
3. hybrid

Pros: Flexible
Cons: Internal types become complicated.

type Events = {
  event1: [],
  event2: [string],
  event3: (id: string, index: number) => void
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions