stencil icon indicating copy to clipboard operation
stencil copied to clipboard

bug: Interface ‘HTMLMyButtonElement’ cannot simultaneously extend types ‘MyButton’ and ‘HTMLStencilElement’. Named property ‘focus’ of types ‘MyButton’ and ‘HTMLStencilElement’ are not identical

Open Unluckynerd opened this issue 2 years ago • 8 comments

Prerequisites

Stencil Version

3.0.1

Current Behavior

Can't compile Stencil because of the typescript error

Error: Interface 'HTMLMyButtonElement' cannot simultaneously extend types 'MyButton' and 'HTMLStencilElement'. Named property 'focus' of types 'MyButton' and 'HTMLStencilElement' are not identical.

Interface 'HTMLMyButtonElement' cannot simultaneously extend types 'MyButton' and 'HTMLStencilElement'.Named property 'focus' of types 'MyButton' and 'HTMLStencilElement' are not identical.

'./src/components.d.ts'
interface HTMLMyButtonElement extends Components.MyButton, HTMLStencilElement {
}

Steps to Reproduce

I want to focus the button element which is inside the my-button, when my-button.focus() is called. Here is the code

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.scss',
  shadow: true,
})

export class MyButton {

  buttonRef: HTMLButtonElement;

  @Prop() disabled = false;

  @Method()
  async focus() {
     this.buttonRef.focus();
  }

  render() {
      return (
        <button
          ref={el => (this.buttonRef = el)}
          disabled={this.disabled}
        >
           <slot />
        </button>
      );
    }
 }

Any ideas how to solve this without modifying typescript config file by adding : compilerOptions > "skipLibCheck": true,

Unluckynerd avatar Jun 09 '23 05:06 Unluckynerd

Hey @Unluckynerd 👋

Can you please provide a full minimal reproduction case for us? I am unable to reproduce the error with the code snippet provided alone.

rwaskiewicz avatar Jun 12 '23 12:06 rwaskiewicz

Thanks for the issue! This issue has been labeled as needs reproduction. This label is added to issues that need a code reproduction.

Please reproduce this issue in an Stencil starter component library and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.

If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for our team to reproduce the issue.

For a guide on how to create a good reproduction, see our Contributing Guide.

ionitron-bot[bot] avatar Jun 12 '23 12:06 ionitron-bot[bot]

@rwaskiewicz Here's the Github repo link of the code. The build is failed due to typescript error

image

Unluckynerd avatar Jun 13 '23 07:06 Unluckynerd

Thanks!

I can see what's happening now - MyButton#focus has a type of () => Promise<void>, which is colliding with HTMLElement provided by TypeScript's lib.dom.dts - focus(options?: FocusOptions): void;. Specifically, the return types are the issue. The former returns a Promise<void>, where the latter returns void.

Since focus is a reserved public name, and Stencil @Methods need to be marked as async, I would recommend renaming MyButton#focus to another name that does not conflict

rwaskiewicz avatar Jun 13 '23 12:06 rwaskiewicz

@rwaskiewicz If I want to use the focus name, Can i use this workaround? Is this right way? Here I am overriding the MyButton#focus in the constructor.

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.scss',
  shadow: true,
})
export class MyButton {

  constructor(){
    this.hostElement.componentOnReady().then(() => {
      this.hostElement.focus = () => this.buttonRef.focus();
    });
  }

  @Element() hostElement;

  buttonRef: HTMLButtonElement;

  @Prop() disabled = false;

  @Event() zClick: EventEmitter;

  handleClick(event) {
    if (this.disabled) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      this.zClick.emit(event);
    }
  }

  render() {
    return (
      <button
        ref={el => (this.buttonRef = el)}
        disabled={this.disabled}
        onClick={event => this.handleClick(event)}
      >
        <slot />
      </button>
    );
  }
}

Heres the repo link

Unluckynerd avatar Jun 13 '23 13:06 Unluckynerd

@Unluckynerd we do not recommend overriding the existing methods available on HTMLElement, such as focus.

In your example, it would be recommended to listen to the focus event from the host and then calling the focus() method from the button reference.

sean-perkins avatar Jun 27 '23 13:06 sean-perkins

@sean-perkins is correct here. We're going to leave this open so that we can see if there are some better options for improving the error messaging here

rwaskiewicz avatar Jun 27 '23 14:06 rwaskiewicz

Having a similar issue where I want to narrow the role attribute to a union type, but it conflicts with HTMLElement's role: string, but it feels like something a custom element should be able to do?

mattclough1 avatar Feb 21 '24 15:02 mattclough1