Skip to content

Allow the use of TypeScript mixins with <svelte:options extend /> #9032

Closed as not planned
@willnationsdev

Description

@willnationsdev

Describe the problem

Related to #4168.

I thought I could work around the lack of base type overrides by at least using mixins to automatically establish some properties on components from a single location using a mixin, like so:

// mixins.ts

type Constructor<T> = new(...args: any[]) => T;

export function CustomElement<T extends Constructor<Element>>(Base: T) {
  return class extends Base {
    constructor(...args: any[]) {
      super(...args);
      this.host = this;
    }
  }
}

export function FormItem<T extends Constructor<HTMLElement>>(Base: T) {
  return class extends CustomElement(Base) {
    static formAssociated = true;

    constructor(...args: any[]) {
      super(...args);
      this.internals = this.attachInternals();
    }
  }
}

Then, import and use those mixins in the extend function, like so:

<!-- my-input.svelte -->
<script context="module">
  import { FormItem } from "./mixins";
</script>

<svelte:options
  customElement={{
    tag: "my-input",
    extend: (ctor) => {
      return class extends FormItem(ctor) {
        // According to a TypeScript GitHub pull request explaining it,
        // TypeScript mixins require a syntax matching the `Constructor<T>`.
        // However, that means we need an `...args: any[]` parameter.
        // If you attempt to add it to the constructor though, Svelte has a parse error.
        constructor() {
          super();
        }
      }
    }
  }}
/>

<script lang="ts">
  export let host: HTMLElement = null;
  export let internals: ElementInternals = null;
  export let name: string;
  export let type: string;
</script>

<input {type} {name} />

Describe the proposed solution

I'd like to be able to adjust the extend lambda so that it looks like this:

{
  extend: (ctor) => {
    return class extends FormItem(ctor) {
      constructor(...args: any[]) {
        super(...args);
      }
    }
  }
}

Alternatives considered

As far as I know (based on the GitHub PR), this is a requirement of the language, so I don't think there are any alternatives available.

As it stands, I have to copy/paste the same base class logic in every single custom element I make with Svelte components that happen to share functionality (not ideal, obviously).

Importance

would make my life easier

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions