Skip to content

fix: ESNext TypeScript compilation option breaks @attr decorator behavior #5017

Open
@rajsite

Description

@rajsite

🐛 Bug Report

When using a TypeScript configuration of "target": "ESNext" creating elements with fast-foundation and fast-element results in attributes not responding to value updates.

For example, for a button modeled after the fast-button implementation:

class Button extends FoundationButton {

    @attr
    public appearance: ButtonAppearance;

    public connectedCallback(): void {
        super.connectedCallback();
        if (!this.appearance) {
            this.appearance = ButtonAppearance.Outline;
        }
    }
}

If the button is initialized without the appearance attribute set in html, <my-button></my-button>, then we expect the connectedCallback to run and update the appearance property and attribute. Checking buttonInstance.appearance returns the value "outline" as expected but the attribute did not update and the expected style did not render. Checking the adoptedStylesheets shows that the additional stylesheet is not attached indicating the behavior did not run.

Investigating shows that the appearance property is set as an owned values, ie buttonInstance.hasOwnProperty('appearance') === true. That value is shadowing the accessors for the appearance field defined by the decorator.

Stepping through the code it looks like setting ESNext enables native class fields. The initializer for the class field in the above example runs and sets the appearance property with the value undefined during construction (didn't nail down the exact timing). Then future property updates manipulate the owned value instead of triggering the accessors on the prototype chain. Stepping into the appearance assignment in the connectedCallback shows that the accessors are not triggered.

💻 Repro or Code Sample

See expected behavior and current behavior.

🤔 Expected Behavior

When using ESNext, and specifically browser native class fields, I'd expect the same behavior as using "target": "ES2020" in my TypeScript configuration. The following shows a stackblitz webcontainer configured for ES2020 and when running shows a button with red text illustrating the appearance correctly propagated. It also shows the hasOwnProperty flag as returning false: https://stackblitz.com/edit/fast-es2020-bug-button?file=src%2Fmain.ts

image

😯 Current Behavior

The following stackblitz webcontainer is configured for ESNext and when running shows a button with black text as the appearance property does not receive the update. It also shows the hasOwnProperty flag as returning true: https://stackblitz.com/edit/fast-esnext-bug-button?file=src%2Fmain.ts

image

💁 Possible Solution

Configure the TypeScript compiler for a target that does not allow ES2022 native browser class fields. For example, in tsconfig.json set "target": "ES2020".

🔦 Context

I would like to leverage native browser features where possible. I may file a separate issue but it would be nice if the other fast builds compiled to a newer TypeScript target than ES6 and relied on consumers who felt like it to use babel, etc. to target older browsers.

Or maybe include both es6 and esnext / es2021 builds in packages so native browser async / await can be used, etc. Benefits are smaller bundle sizes (generator and generator polyfills aren't injected for async / await and other features that are native).

Edit: Looks like the interactions of class fields and accessors is unintuitive at first glance for lots of folks. They newer decorators proposals may have what's needed for attribute interactions.

🌍 Your Environment

  • macOS Big Sur 11.5.1 (20G80)
  • Version 92.0.4515.107 (Official Build) (x86_64)
  • @microsoft/fast-foundation 2.6.2
  • @microsoft/fast-foundation 1.4.1
  • typescript 4.3.5
  • webpack 5.47.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:fast-elementPertains to fast-elementbugA bugcommunity:noteworthyAn issue or PR of particular interest to the community or planned for an announcement.status:needs-investigationNeeds additional investigation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions