Skip to content

Commit 39ad574

Browse files
authored
Add support for "private" custom elements (#1943)
In typescript, users can specify a private constructor to prevent subclassing ```ts class XFoo extends HTMLElement { private constructor() { super(); } } ``` In order to support this construction with `@customElement`, we have to switch from using `Constructor<HTMLElement>` to `Omit<typeof HTMLElement, 'new'>`.
1 parent 660192d commit 39ad574

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

packages/reactive-element/src/decorators/custom-element.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
*/
1313
import {Constructor, ClassDescriptor} from './base.js';
1414

15-
const legacyCustomElement = (
16-
tagName: string,
17-
clazz: Constructor<HTMLElement>
18-
) => {
19-
window.customElements.define(tagName, clazz);
15+
/**
16+
* Allow for custom element classes with private constructors
17+
*/
18+
type CustomElementClass = Omit<typeof HTMLElement, 'new'>;
19+
20+
const legacyCustomElement = (tagName: string, clazz: CustomElementClass) => {
21+
window.customElements.define(tagName, clazz as CustomElementConstructor);
2022
// Cast as any because TS doesn't recognize the return type as being a
2123
// subtype of the decorated class when clazz is typed as
2224
// `Constructor<HTMLElement>` for some reason.
@@ -57,7 +59,7 @@ const standardCustomElement = (
5759
*/
5860
export const customElement =
5961
(tagName: string) =>
60-
(classOrDescriptor: Constructor<HTMLElement> | ClassDescriptor) =>
62+
(classOrDescriptor: CustomElementClass | ClassDescriptor) =>
6163
typeof classOrDescriptor === 'function'
6264
? legacyCustomElement(tagName, classOrDescriptor)
63-
: standardCustomElement(tagName, classOrDescriptor);
65+
: standardCustomElement(tagName, classOrDescriptor as ClassDescriptor);

packages/reactive-element/src/test/decorators/customElement_test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,15 @@ suite('@customElement', () => {
1616
const DefinedC = customElements.get(tagName);
1717
assert.strictEqual(DefinedC, C0);
1818
});
19+
test('elements with private constructors can be defined', () => {
20+
const tagName = generateElementName();
21+
@customElement(tagName)
22+
class C1 extends HTMLElement {
23+
private constructor() {
24+
super();
25+
}
26+
}
27+
const DefinedC = customElements.get(tagName);
28+
assert.strictEqual(DefinedC, C1);
29+
});
1930
});

0 commit comments

Comments
 (0)