Skip to content

fix: form-associated base classes need stubs for mixin classes with private/protected members #5061

@radium-v

Description

@radium-v

🐛 Bug Report

Any form-associated components that use the FormAssociated() mixin function require the use of a stub class and interface for TypeScript to properly handle private/protected members.

💻 Repro or Code Sample

Ideally, we'd be able to create these stubs for form-associated components:

import { FormAssociated } from "../form-associated/form-associated";
import { FoundationElement } from "../foundation-element";

export class FormAssociatedComponent extends FormAssociated(
    class extends FoundationElement {
        public proxy: HTMLInputElement = document.createElement("input");
    }
) {}

export interface FormAssociatedComponent extends FormAssociated {}

😯 Current Behavior

TS throws errors on the properties in FoundationElement which are private or protected:

error TS4094: Property '$presentation' of exported class expression may not be private or protected.
error TS4094: Property '_presentation' of exported class expression may not be private or protected.
error TS4094: Property 'stylesChanged' of exported class expression may not be private or protected.
error TS4094: Property 'templateChanged' of exported class expression may not be private or protected.

💁 Solution

The workaround for this bug requires creating an empty base class which extends FoundationElement (or the base component class, ex. Listbox) and its interface which extends FormAssociated. This class should be passed to the FormAssociated() function. The proxy property should then be defined in the class body instead of in the stub class.

import { FormAssociated } from "../form-associated/form-associated";
import { FoundationElement } from "../foundation-element";

class _Component extends FoundationElement {}
interface _Component extends FormAssociated {}

export class FormAssociatedComponent extends FormAssociated(_Component) {
    public proxy: HTMLInputElement = document.createElement("input");
}

export interface FormAssociatedComponent extends FormAssociated {}

🔦 Context

microsoft/TypeScript#30355
microsoft/TypeScript#36060
microsoft/TypeScript#17744 (comment)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions