ionic-team / stencil-ds-output-targets

These are output targets that can be added to Stencil for React and Angular.
https://stenciljs.com
MIT License
250 stars 118 forks source link

Angular binding error : Argument of type 'Event' is not assignable to parameter of type CustomEvent #219

Open viico opened 2 years ago

viico commented 2 years ago

Hi,

We use Stencil to build a web component library. We follow the stencil's guide Angular Integration (https://stenciljs.com/docs/angular) in order to create an angular library to use our web components in an angular project.

In the target project, with strictTemplates key at true, we can't use the generic type CustomEvent for web component events in our application.

The error is :

Error: src/app/app.component.html:1:74 - error TS2345: Argument of type 'Event' is not assignable to parameter of type 'CustomEvent<NameClickedEvent>'.
  Type 'Event' is missing the following properties from type 'CustomEvent<NameClickedEvent>': detail, initCustomEvent

1 <my-component first="Stencil" last="Compiler" (nameClicked)="nameClicked($event)"></my-component>

We pushed a minimal repository to reproduce the error :

  1. clone the repo https://github.com/viico/angular-output-target-custom-event
  2. npm install and npm run build in stencil-library folder
  3. npm install and npm run build in angular-workspace folder
  4. npm install and ng serve in my-app folder => errors occurs during ng serve

It works if we set strictTemplates at false or if we use any or Event type but these solutions are not feasible.

//nameClicked($event: any) { // works
nameClicked($event: CustomEvent<NameClickedEvent>) { // fails
  console.log($event);
}

After a 2 day search we don't see what we did wrong, could you help us to find the problem ?

Thanks

viico commented 2 years ago

I forgot an information.

When I manually update the auto-generated angular directive proxies file to add the outputs key in the Component decorator, it fixes the error, but the event is trigger twice (relative to this PR https://github.com/ionic-team/stencil-ds-output-targets/pull/202).

@Component({
  selector: 'my-component',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: '<ng-content></ng-content>',
  inputs: ['first', 'last', 'middle'],
  outputs: ['nameClicked'] // fix the error, but event is trigger twice
})
mmacret commented 1 year ago

Any updates on this? it is really making it hard to use the Angular wrappers...

tfrijsewijk commented 1 year ago

I'm curious as well. I have a patch that I keep up to date with every @stencil/angular-output-target release.. but most of all, how is anyone working with Angular wrappers and events? We can't get it to work anywhere without the changes suggested in https://github.com/ionic-team/stencil-ds-output-targets/pull/308

m-thompson-code commented 1 year ago

Is there any good advice for the short term? Should I use https://github.com/ionic-team/stencil-ds-output-targets/pull/308 until there's a better solution out there?

m-thompson-code commented 1 year ago

A workaround to this issue that I've used is to define a HTMLElementTagNameMap where I define event listeners for each Event:

/** src/my-types.d.ts */
declare global {
  type EventName = "my-event";
  interface HTMLMyComponentElement {
      addEventListener<EventName>(type: EventName, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<boolean>) => any, options?: boolean | AddEventListenerOptions): void;
      addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
      removeEventListener<EventName>(type: EventName, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<boolean>) => any, options?: boolean | EventListenerOptions): void;
      removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
  }

  interface HTMLElementTagNameMap {
      "my-component": HTMLMyComponentElement;
  }
}

I've created a PR to make this part of Stencil's compiler: https://github.com/ionic-team/stencil/pull/4909 And you can use this output target to generate these event listener types for your project: https://github.com/m-thompson-code/event-listener-types-output-target#event-listener-types-output-target