@property decorator incompatible with tsconfig compilerOption useDefineForClassFields

Open
#10,202 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Needs clarification
Activity status
Stale
Tech stack
typescript
Domain
frontend

Research direction

Start by reproducing the custom-element example with TypeScript's useDefineForClassFields enabled, then inspect the warning in packages/base/src/UI5Element.ts around line 280. Determine how the decorator and compiler option interact, and document the supported alternatives, including declare and constructor defaults, with a clear expected outcome.

Written by the indexing model from the issue text.

Description

bug documentation TOPIC Core
Bug Description

Hello,

I created a custom element and defined a property. However, setting the property did not change the attribute value in DOM.

After debugging a lot, I think I've tracked this down to the typescript compiler. You can just use the simple example from the playground and add "useDefineForClassFields" = true in the compilerOptions.

Also, there is even a warning (but only in DEV mode - would have saved me some time....) in this case: https://github.com/SAP/ui5-webcomponents/blob/63de8f0aa13fc6bd92748cc7416cf873887c0de5/packages/base/src/UI5Element.ts#L280

However, as stated in the warning, the solution cannot be to "not use useDefineForClassFields" or "not use ES2022" (which will default useDefineForClassFields to true, see https://www.typescriptlang.org/tsconfig/#useDefineForClassFields)?

Following the documentation, you can easily fix the issue by just adding a declare to the property as this will not emit any JS Code. Since the JS Code (additional defineProperty() after the super-constructor was called, which already generates the getter and setters based on the element metadata):

...

@customElement({
  tag: "my-element",
  renderer: litRender,
})
export class MyElement extends UI5Element {
  @property()
  declare name?: string;

  render() {
    return html `
      <div>
          Hello, ${this.name || "World"}!
      </div>`
  }

...

The only downside is, that you cannot declare a default value for this property then... so if the default for name should be UI5, you would need to write:

...

@customElement({
  tag: "my-element",
  renderer: litRender,
})
export class MyElement extends UI5Element {
  @property()
  declare name?: string;

    constructor() {
        super();
        this.name = "UI5"; // default
    }

  render() {
    return html `
      <div>
          Hello, ${this.name || "World"}!
      </div>`
  }

...

So what's the best option to solve this issue? I think at least the documentation should address this issue and show the alternatives?

Affected Component

No response

Expected Behaviour

No response

Isolated Example

No response

Steps to Reproduce

...

Log Output, Stack Trace or Screenshots

No response

Priority

None

UI5 Web Components Version

2.4.0

Browser

Chrome

Operating System

No response

Additional Context

No response

Organization

No response

Declaration
  • I’m not disclosing any internal or sensitive information.
Dominant language
TypeScript
Stars
1.8k
Forks
285
Avg merge
3d 2h
Merged PRs (30d)
59

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from UI5/webcomponents

All issues in UI5/webcomponents

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.