Skip to content

Commit 1040f75

Browse files
justinfagnaniAndrewJakubowiczrictic
authored
Change the type of renderRoot to include Element (#4254)
* Use a Mutable<T, K> type to more accurate casts * Change the type of renderRoot to include Element * Change createRenderRoot too * Update check-size script * Update check-size.js --------- Co-authored-by: Andrew Jakubowicz <ajakubowicz@google.com> Co-authored-by: Peter Burns <rictic@google.com>
1 parent f14fc2f commit 1040f75

3 files changed

Lines changed: 26 additions & 15 deletions

File tree

.changeset/fresh-goats-suffer.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@lit/reactive-element': major
3+
'lit-element': major
4+
'lit': major
5+
---
6+
7+
Change the type of `ReactiveElement.renderRoot` and return type of `ReactiveElement.createRenderRoot()` to be `HTMLElement | DocumentFragment` to match each other and lit-html's `render()` method.

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ export type {
3030
ReactiveControllerHost,
3131
} from './reactive-controller.js';
3232

33+
/**
34+
* Removes the `readonly` modifier from properties in the union K.
35+
*
36+
* This is a safer way to cast a value to a type with a mutable version of a
37+
* readonly field, than casting to an interface with the field re-declared
38+
* because it preserves the type of all the fields and warns on typos.
39+
*/
40+
type Mutable<T, K extends keyof T> = Omit<T, K> & {
41+
-readonly [P in keyof Pick<T, K>]: P extends K ? T[P] : never;
42+
};
43+
3344
// TODO (justinfagnani): Add `hasOwn` here when we ship ES2022
3445
const {
3546
is,
@@ -660,11 +671,9 @@ export abstract class ReactiveElement
660671
name: PropertyKey,
661672
options: PropertyDeclaration = defaultPropertyDeclaration
662673
) {
663-
// if this is a state property, force the attribute to false.
674+
// If this is a state property, force the attribute to false.
664675
if (options.state) {
665-
// Cast as any since this is readonly.
666-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
667-
(options as any).attribute = false;
676+
(options as Mutable<PropertyDeclaration, 'attribute'>).attribute = false;
668677
}
669678
this.__prepare();
670679
this.elementProperties.set(name, options);
@@ -925,7 +934,7 @@ export abstract class ReactiveElement
925934
* to an open shadowRoot.
926935
* @category rendering
927936
*/
928-
readonly renderRoot!: HTMLElement | ShadowRoot;
937+
readonly renderRoot!: HTMLElement | DocumentFragment;
929938

930939
/**
931940
* Returns the property name for the given attribute `name`.
@@ -1077,7 +1086,7 @@ export abstract class ReactiveElement
10771086
* @return Returns a node into which to render.
10781087
* @category rendering
10791088
*/
1080-
protected createRenderRoot(): Element | ShadowRoot {
1089+
protected createRenderRoot(): HTMLElement | DocumentFragment {
10811090
const renderRoot =
10821091
this.shadowRoot ??
10831092
this.attachShadow(
@@ -1096,14 +1105,9 @@ export abstract class ReactiveElement
10961105
* @category lifecycle
10971106
*/
10981107
connectedCallback() {
1099-
// create renderRoot before first update.
1100-
if (this.renderRoot === undefined) {
1101-
(
1102-
this as {
1103-
renderRoot: Element | DocumentFragment;
1104-
}
1105-
).renderRoot = this.createRenderRoot();
1106-
}
1108+
// Create renderRoot before first update.
1109+
(this as Mutable<typeof this, 'renderRoot'>).renderRoot ??=
1110+
this.createRenderRoot();
11071111
this.enableUpdating(true);
11081112
this.__controllers?.forEach((c) => c.hostConnected?.());
11091113
}

scripts/check-size.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as fs from 'fs';
99
// it's likely that we'll ask you to investigate ways to reduce the size.
1010
//
1111
// In either case, update the size here and push a new commit to your PR.
12-
const expectedLitCoreSize = 15467;
12+
const expectedLitCoreSize = 15441;
1313
const expectedLitHtmlSize = 7256;
1414

1515
const litCoreSrc = fs.readFileSync('packages/lit/lit-core.min.js', 'utf8');

0 commit comments

Comments
 (0)