Skip to content
Meeko
Type to search the guides and the API reference. Open it from any page with / or Ctrl K; move with the arrow keys and open a result with Enter.
Get started

Contents

On this page

defineEmits

Declares a component's events with typed arguments and returns emit, which calls the parent's on:evento handler.

macro Since 1.1.0 Source code

defineEmits<T>() declares the component's events: each key of T is an event and its value is the argument tuple. It returns emit(evento, ...args), typed with those tuples. It is a compile-time macro: you do not import it.

There is no separate event channel: each save event is the child's optional onSave callback prop, and emit("save", id) calls the one currently passed by the parent with on:save. Without a listener, emit does nothing.

Usage#

meeko
<!-- app/components/TodoItem.meeko -->
<script lang="ts">
const props = defineProps<{ id: number; title: string }>();
const emit = defineEmits<{ save: [id: number]; close: [] }>();
</script>

<template>
  <p>{props.title}</p>
  <button type="button" on:click="() => emit('save', props.id)">Save</button>
  <button type="button" on:click="() => emit('close')">Close</button>
</template>
meeko
<!-- in the parent -->
<TodoItem bind:id="todo.id" bind:title="todo.title" on:save="(id) => save(id)" on:close="() => open.value = false" />

Type#

ts
const emit = defineEmits<{ save: [id: number]; close: [] }>()
emit('save', 42)

Parameters#

Parameter Type Default Description
T (type argument) { [evento]: [...args] } required An object whose keys are events (identifiers) and whose values are named tuples: { save: [id: number]; close: [] }. Omitting it produces MEEK046.

Does not accept runtime arguments (MEEK047): events are declared only in the type.

Return value#

emit(evento, ...args): void. TypeScript checks that evento is a key of T and that arguments match its tuple. emit synchronously calls the parent's current on<Evento> prop; if the parent does not pass one, it does nothing.

In the parent, ComponentProps includes an optional on<Evento> prop per event (onSave?: (id: number) => unknown), and on:save="…" fills it.

Examples#

An event with multiple arguments#

Named tuples document each argument in the editor:

meeko
<!-- app/components/AppRating.meeko -->
<script lang="ts">
const props = defineProps<{ max?: number }>({ max: 5 });
const emit = defineEmits<{ rate: [value: number, previous: number | null] }>();
const value = signal<number | null>(null);
function pick(next: number): void {
  const previous = value.value;
  value.value = next;
  emit("rate", next, previous);
}
const stars = computed(() => Array.from({ length: props.max }, (_, index) => index + 1));
</script>

<template>
  <button each:of="stars.value" each:as="star" type="button" bind:aria-pressed="value.value === star ? 'true' : 'false'" on:click="() => pick(star)">{star}</button>
</template>
meeko
<AppRating on:rate="(value, previous) => console.log(value, previous)" />

Forward a child's event#

A wrapper component can forward its child's event with its own emit:

meeko
<!-- app/components/TodoRow.meeko -->
<script lang="ts">
const props = defineProps<{ id: number; title: string }>();
const emit = defineEmits<{ save: [id: number] }>();
</script>

<template>
  <li><TodoItem bind:id="props.id" bind:title="props.title" on:save="(id) => emit('save', id)" /></li>
</template>

Generic events#

In a component with generic, the tuple can use the parameter, and the parent receives the type inferred from props:

meeko
<!-- app/components/AppList.meeko -->
<script lang="ts" generic="T extends { id: string }">
const props = defineProps<{ items: T[] }>();
const emit = defineEmits<{ select: [item: T] }>();
</script>

<template>
  <ul><li each:of="props.items" each:as="item" each:key="item.id" on:click="() => emit('select', item)">{item.id}</li></ul>
</template>

Common mistakes#

No type argument, or runtime arguments#

Incorrectmeeko
<script lang="ts">
const emit = defineEmits(["save"]);
</script>

MEEK046: defineEmits necesita un argumento de tipo, como defineEmits<{ save: [id: number] }>(). With a type argument and arguments (defineEmits<…>(["save"])), MEEK047: defineEmits no admite argumentos en tiempo de ejecución; declara los eventos en su argumento de tipo.

Correctmeeko
<script lang="ts">
const emit = defineEmits<{ save: [id: number] }>();
</script>

let, destructuring or two calls#

Incorrectmeeko
<script lang="ts">
let emit = defineEmits<{ save: [id: number] }>();
</script>

MEEK045: defineEmits debe aparecer una sola vez, en su propia declaración const de nivel superior con un nombre simple.

Correctmeeko
<script lang="ts">
const emit = defineEmits<{ save: [id: number] }>();
</script>

Arguments that do not match the tuple#

Incorrectmeeko
<button on:click="() => emit('save', String(props.id))">Save</button>

meeko check reports TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Correctmeeko
<button on:click="() => emit('save', props.id)">Save</button>

The same callback in defineProps#

Incorrectmeeko
<script lang="ts">
const props = defineProps<{ id: number; onSave?: (id: number) => void }>();
const emit = defineEmits<{ save: [id: number] }>();
</script>

meeko check reports TS2344: Type '"defineEmits events conflict with defineProps props: onSave"' does not satisfy the constraint 'true'.

Correctmeeko
<script lang="ts">
const props = defineProps<{ id: number }>();
const emit = defineEmits<{ save: [id: number] }>();
</script>

A parent handler with different arguments#

Incorrectmeeko
<TodoItem bind:id="1" bind:title="'Tea'" on:save="(id: string) => save(id)" />

meeko check reports TS2322: Type '(id: string) => void' is not assignable to type '(id: number) => void'. An undeclared child event (on:remove) produces TS2353, and a hyphenated name (on:save-draft) produces MEEK011.

Correctmeeko
<TodoItem bind:id="1" bind:title="'Tea'" on:save="(id) => save(String(id))" />

Notes#

  • Server or browser. emit only has an effect in the browser, inside a handler or effect. Handlers do not run in SSR.
  • Errors. The parent's handler runs synchronously inside the child's emit: if it throws, the error escapes emit. When called from a child's on:, it reaches the error observer like any listener failure, with source "event".
  • Names. Events are identifiers (save, saveDraft); the parent listens with on:save, on:saveDraft. on:save and bind:onSave on the same tag produce MEEK048.
  • Location. Once, in its own top-level const declaration, before the first browser await (MEEK058).
  • Values in both directions. For a value shared by parent and child (an open, a value), defineModel avoids the prop + event pair.

Was this page helpful?

Add a comment

It is sent when you choose “Yes” or “No”. Only the page, your answer and the comment are stored: no cookies and no personal data.

0 of 2000 characters

Edit on GitHub: docs/en/reference/macros/defineemits.md