oxc-project/oxc · error
Inline helpers are not supported yet
Error message
Inline helpers are not supported yet
What it means
Diagnostic from oxlint's vue/valid-define-emits rule (crates/oxc_linter/src/rules/vue/valid_define_emits.rs). It fires when `defineEmits()` is called with neither an argument nor a type parameter and the SFC's sibling plain `<script>` block does not provide `emits` on its default export — so no events are declared anywhere. Undeclared events break the component contract, devtools introspection, and Vue's attribute-fallthrough behavior.
Source
Thrown at crates/oxc_transformer/src/common/helper_loader.rs:321
let existing = ctx.state.helper_loader.loaded_helpers.get(&helper).cloned();
if let Some(binding) = existing {
return binding.create_read_expression(ctx);
}
// Generate new binding
let is_module = ctx.state.source_type.is_module();
let flag =
if is_module { SymbolFlags::Import } else { SymbolFlags::FunctionScopedVariable };
let binding = ctx.generate_uid_in_root_scope(helper.name(), flag);
ctx.state.module_imports.add_default_import(source, binding.clone(), false);
ctx.state.helper_loader.loaded_helpers.insert(helper, binding.clone());
binding.create_read_expression(ctx)
}
HelperLoaderMode::External => HelperLoaderStore::transform_for_external_helper(helper, ctx),
HelperLoaderMode::Inline => {
unreachable!("Inline helpers are not supported yet");
}
}
}
// Internal methods
impl<'a> HelperLoaderStore<'a> {
// Construct string directly in arena without an intermediate temp allocation
fn get_runtime_source(&self, helper: Helper, ctx: &TraverseCtx<'a>) -> Str<'a> {
Str::from_strs_array_in([&self.module_name, "/helpers/", helper.name()], ctx)
}
fn transform_for_external_helper(helper: Helper, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
let helper_var = static_ident!("babelHelpers");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), helper_var);
let object = ctx.create_ident_expr(SPAN, helper_var, symbol_id, ReferenceFlags::Read);
let property = IdentifierName::new(SPAN, helper.name(), ctx);
Expression::new_static_member_expression(SPAN, object, property, false, ctx)
}View on GitHub (pinned to e1e7af627c)
Solutions
- Declare the events: `defineEmits(['notify'])`, an object with validators, or a TS call-signature type.
- If the component emits nothing, remove the defineEmits call and any emit usages entirely.
- Alternatively keep events in the sibling `<script>`'s `export default { emits: [...] }` and leave `defineEmits()` bare — but declaring next to the macro is clearer.
Example fix
// before const emit = defineEmits(); // after const emit = defineEmits(['notify', 'submit']);
Defensive patterns
Strategy: validation
Validate before calling
// a bare defineEmits() must be accompanied by options emits or removed
const m = setupSource.match(/defineEmits\s*(<[^>]*>)?\s*\(([^)]*)\)/);
if (m && !m[1] && !m[2].trim() && !optionsBlockHasEmits) {
throw new Error('defineEmits() declares no events');
} Prevention
- Never scaffold `const emit = defineEmits()` without listing events.
- If the component emits nothing, delete the macro and any emit calls.
- Declare events where they are emitted, next to the macro call.
When it happens
Trigger: A bare `defineEmits()` in `<script setup>` when there is no `export default { emits: ... }` in another script block of the same SFC. Declaring events via array, object, type parameter, or the options block avoids it; `defineEmits(unresolvedVariable)` is not reported because the events cannot be statically known.
Common situations: Scaffolding `const emit = defineEmits()` as boilerplate before events are known; refactoring events out of the options API but leaving the macro call empty.
Related errors
- [HIRBuilder] expected block {:?} to exist
- TS5042
- TS5081
- invalid fix kind: {s}. Valid fix kinds are fix, suggestion,
- `defineOptions()` cannot be used to declare `{prop_name}`. U
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/5d5c67ba611c03ab.
Report an issue: GitHub.