Skip to content

WIP (alpha): expose component events/slots, emit value+type default export#910

Draft
baseballyama wants to merge 1 commit into
feat/virtual-component-export-genericsfrom
feat/virtual-component-export-events-slots
Draft

WIP (alpha): expose component events/slots, emit value+type default export#910
baseballyama wants to merge 1 commit into
feat/virtual-component-export-genericsfrom
feat/virtual-component-export-events-slots

Conversation

@baseballyama

Copy link
Copy Markdown
Member

Warning

🚧 Work In Progress — Alpha. Do not merge.
Alpha-stage work authored by Claude Code (AI), published as a draft for early review only. Behavior/API may change or be dropped.

Note

Stacked on #909 (→ #908#907#906#905). Review the parents first.

What

PR 6 of 6 (final) — events / slots, plus a regression fix.

The regression this fixes

Investigating the consumer side showed the parser references an imported component's legacy events via import('svelte').ComponentEvents<Foo> — using Foo as a type. But PRs #905#909 emitted a value-only export default <expr>, so Foo had no type meaning and ComponentEvents<Foo> failed with:

TS2749: 'Foo' refers to a value, but is being used as a type here.

(For bind: and slots, the consumer generates no component-type reference, so those need nothing on the producer side. Runes event props like onclick already flow through ComponentProps.)

The fix

Emit the default export as a value + type pair, so Foo works as both:

declare const $c: import('svelte').SvelteComponent<Props, Events, Slots>;
type $c = import('svelte').SvelteComponent<Props, Events, Slots>;
export { $c as default };

This redesigns the emitted form from Component<Props> to the SvelteComponent value/type pair, so the #905#909 string-assertion tests are updated here to match (behavior/E2E tests are unchanged).

Verified

  • Full suite green (8680 passing), incl. AST/scope invariance.
  • New unit tests: $$Events/$$Slots wired in; export carries both value and type.
  • New end-to-end tsc tests: legacy $$Events event detail resolves (CustomEvent<number>); Foo usable as a type with no TS2749 even without $$Events.

Series (complete)

🤖 Generated with Claude Code

…t (alpha)

Final part of the importer-facing component type series. Emit the synthetic
default export as a value/type pair re-exported as default:

  declare const $c: import('svelte').SvelteComponent<Props, Events, Slots>;
  type $c = import('svelte').SvelteComponent<Props, Events, Slots>;
  export { $c as default };

This fixes legacy `on:` event consumers: the parser references components via
`ComponentEvents<Foo>` (using `Foo` as a type), which the previous value-only
`export default` broke with TS2749 ("Foo refers to a value, used as a type").
`Events`/`Slots` are recovered from legacy `$$Events`/`$$Slots` when present, else
permissive. Props resolution via `ComponentProps<typeof Foo>` is unchanged. All
three synthetic statements are removed again in the restore pass (AST/scope
invariance suite stays green).

Experimental, alpha-stage, implemented by Claude Code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 41fa3ef

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte-eslint-parser Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant