Stencil: Sudden build error without message after adding `@Method` to component

1.2k Views Asked by At

I cannot give too much information here (because there really isn't), but only this:

All of the sudden, after adding a @Method function to a stencil component:

@Method()
async setMenuItems(items: Element[]): Promise<void> {
  // code here
} 

the component stopped compiling with the following - really unhelpful - error:

[ ERROR ]  ./src/components/menu-content/menu-content.tsx:63:44
           build error

     L62:  @Method()
     L63:  async setMenuItems(elements: Element[]): Promise<void> {
     L64:    const unsupportedChildren = elements.filter(e => !this.isSupportedChild(e)).map(e => e.tagName);

[12:37.1]  build failed in 7.02 s

Things to notice

  • the return type Promise<void> inside the error-message is highlighted red
  • there are other @Methods that do work within this component (even with the same return type).
  • the "broken" @Method is structurally equal to those that do work.
  • TypeScript compiler does not complain about anything
  • Only stencil compiler fails

I already tried...

  • to google for this issue - did not find any hints to this problem
  • to remove the async and add return Promise.resolve()
  • to rename the method (I mean.. why not)
  • to move the method to another place in class
  • to remove the whole method (compiles fine x( )
  • to remove the @Method decorator (compiled, but of course my method is removed from API)
  • to delete node_modules folder and reinstall

I remember that I already had this error once, and apparently I somehow fixed it (or not, idk). But if I did, I cannot remember how.

Does anyone have an idea how to debug this - or even better fix?

2

There are 2 best solutions below

2
On BEST ANSWER

I figured it out. A more complete version of my component is:

import { Element, ... } from '@stencil/core';

class MenuContent {
  @Element() element: MenuContentElement;

  @Method()
  setMenuItems(elements: Element[]): Promise<void> {
    // ------------------^^^^^^^
    // Element is meant to be the built-in browser interface for Element
    // but stencil thinks that this is the imported Element from '@stencil/core'!
  }
}

The exact problem here is, that the stencil-compiler seems to assume that the elements parameter is of type Element that is imported from @stencil/core which is obviously wrong and leads to this strange unhelpful error.

Possible Solutions

1. Use an alias type for the built-in Element type

// types.ts
export type DomElement = Element;

// menu-content.tsx
import { DomElement } from './types';
...
async setMenuItems(elements: DomElement[]): Promise<void> { ... }

2. Switch to HTMLElement

Note: This is only legit, when you don't need to support other Element-types such as SVGElements for example!

async setMenuItems(elements: HTMLElement[]): Promise<void> { ... }

3. Use alias in import statement

Please note: When using @stencil eslint rules, they will complain about your renamed import and say that "own class members are not allowed to be public".

I created a ticket for it here: https://github.com/ionic-team/stencil-eslint/issues/28

import { Element as ElementDecorator} from '@stencil/core';

class MenuContent {
  // eslint will complain about that:
  // "Own class properties cannot be public."
  @ElementDecorator() element: HTMLMenuContentElement;
}
1
On

I experienced this same issue not with the Element type but with the Event type, so it appears to be rooted deeper - also about a year after you reported this issue it seems to still be a problem with Stencil