1

When subclassing a lit-element Class to add further typing, should the @property decorator be overridden or just the type and initializer? In otherwords, suppose I have this code:

interface AB {
   a: number,
   b: string,
}

@customElement('my-parent')
class MyParent extends LitElement {
    @property({type: Array}) stuff: readonly any[] = [];
}

which of the following would be right as a way of subclassing:

@customElement('my-child')
class MyChild extends MyParent {
    override @property({type: Array}) stuff: readonly Readonly<AB>[] = [];
}

or

@customElement('my-child')
class MyChild extends MyParent {
    override stuff: readonly Readonly<AB>[] = [];
}

Both seem to be working in my codebase, so I'm not sure which to standardize to.

0

1 Answer 1

1

Both syntax working I think is more of a quirk of TypeScript's original implementation of class fields with useDefineForClassFields: false where "overridden" class fields still end up invoking accessor added by the decorator on a superclass field.

Semantically it makes more sense that overridden properties must also be decorated separately and shouldn't inherit previously decorated behavior. Thus your first case (using @property in base and subclass) will be the only one that works when using standard decorators for Lit reactive properties which will require the accessor keyword to turn class fields into accessors.

See the TypeScript 3.7 Announcement, for more details, especially the section, "This can cause quite a bit of fallout for existing code that use inheritance. First of all, set accessors from base classes won’t get triggered - they’ll be completely overwritten."

Note that useDefineForClassFields is switched to true by default if the lib includes "es2022" or later or "esNext".


Below is an older version of my answer which was incorrect.

It's odd that you're marking @property on something that's readonly since the point of @property is to make it reactive to trigger an update on set, which readonly implies you won't do.

In any case, overriding the class property in a subclass without @property will remove the reactivity.

Sign up to request clarification or add additional context in comments.

5 Comments

It's odd that you're marking @property on something that's readonly: for arrays and records/objects, it's standard to mark them as readonly/Readonly since mutating the array or object (with .push() etc.) will not trigger a reactive update. You need to do something like this.stuff = [...this.stuff, 'new stuff']
Ah, you are correct! I misread the readonly array alternate syntax for readonly class fields. I updated the answer to cross that out as well as answer the question better. Sorry!
Thank you Augustine for the much improved answer with the reference to "useDefineForClassFields" -- mind if I change "should also be decorated themselves" to "would need to also be decorated themselves"? I first read it as implying "should have been done for you" (meaning, DON'T add the override @property() stuff: ... but just write override stuff: ... ) which is the opposite of what you intended.
I went ahead and made that change, and added some links. The part about lib version also explains why I've been seeing one behavior in one project (still on ES6) and other behavior on another (on "es2023")
Excellent clarification, thank you!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.