Skip to content

Commit de86252

Browse files
authored
Update doc regarding class fields (#1244)
1 parent 381119c commit de86252

File tree

2 files changed

+61
-24
lines changed

2 files changed

+61
-24
lines changed

packages/lit-dev-content/site/docs/v3/components/decorators.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ TypeScript supports both experimental decorators and standard decorators. We rec
7676

7777
To use experimental decorators you must enable the `experimentalDecorators` compiler option.
7878

79-
You should also ensure that the `useDefineForClassFields` setting is `false`. Note, this is only required when the `target` is set to `ES2022` or greater, but it is recommended to explicitly set this to `false`.
79+
You should also ensure that the `useDefineForClassFields` setting is `false`. This is only required when `target` is set to `ES2022` or greater, but it is recommended to explicitly set this to `false`. This is needed to [avoid issues with class fields when declaring properties](/docs/v3/components/properties/#avoiding-issues-with-class-fields).
8080

8181
```json
8282
// tsconfig.json
@@ -125,12 +125,6 @@ Enable decorators by adding [`@babel/plugin-proposal-decorators`](https://babelj
125125

126126
Note: Lit decorators only work with `"version": "2023-05"`. Other versions, including the formerly supported `"2018-09"`, are not supported.
127127

128-
### Avoiding issues with class fields and decorators {#avoiding-issues-with-class-fields}
129-
130-
Standard [class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields) have a problematic interaction with declaring reactive properties. See [Avoiding issues with class fields when declaring properties](/docs/v3/components/properties/#avoiding-issues-with-class-fields) for more information.
131-
132-
When using decorators, transpiler settings for Babel and TypeScript must be configured correctly as shown in the sections above for [TypeScript](#decorators-typescript) and [Babel](#decorators-babel).
133-
134128
## Decorator versions
135129

136130
Decorators are a [stage 3 proposal](https://github.com/tc39/proposal-decorators) for addition to the ECMAScript standard. Compilers like [Babel](https://babeljs.io/) and [TypeScript](https://www.typescriptlang.org/) support decorators, though no browsers have implemented them yet. Lit decorators work with Babel and TypeScript, and will work in browsers when they implement them natively.

packages/lit-dev-content/site/docs/v3/components/properties.md

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,34 +120,77 @@ An empty option object is equivalent to specifying the default value for all opt
120120

121121
### Avoiding issues with class fields when declaring properties {#avoiding-issues-with-class-fields}
122122

123-
[Class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields) have a problematic interaction with reactive properties. Class fields are defined on the element instance. Reactive properties are defined as accessors on the element prototype. According to the rules of JavaScript, an instance property takes precedence over and effectively hides a prototype property. This means that reactive property accessors do not function when class fields are used. When a property is set, the element does not update.
123+
[Class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields) have a problematic interaction with reactive properties. Class fields are defined on the element instance whereas reactive properties are defined as accessors on the element prototype. According to the rules of JavaScript, an instance property takes precedence over and effectively hides a prototype property. This means that reactive property accessors do not function when class fields are used such that setting the property won't trigger an element update.
124124

125-
In **JavaScript** you **must not use class fields** when declaring reactive properties. Instead, properties must be initialized in the element constructor:
125+
```js
126+
class MyElement extends LitElement {
127+
static properties = {foo: {type: String}}
128+
foo = 'Default'; // ❌ this will make `foo` not reactive
129+
}
130+
```
126131

132+
In **JavaScript**, you **must not use class fields** when declaring reactive properties. Instead, properties must be initialized in the element constructor:
127133
```js
128-
constructor() {
129-
super();
130-
this.data = {};
134+
class MyElement extends LitElement {
135+
static properties = {foo: {type: String}}
136+
constructor() {
137+
super();
138+
this.foo = 'Default';
139+
}
131140
}
132141
```
133142

134-
For **TypeScript**, you **may use class fields** for declaring reactive properties as long as you use one of these patterns:
135-
* Set the `useDefineForClassFields` setting in your `tsconfig` to `false`. Note, this is not required for some configurations of TypeScript, but it's recommended to explicitly set it to `false`.
136-
* Add the `declare` keyword on the field, and put the field's initializer in the constructor.
143+
Alternatively, you may use [standard decorators with Babel](/docs/v3/components/decorators/#decorators-babel) to declare reactive properties.
144+
```ts
145+
class MyElement extends LitElement {
146+
@property()
147+
accessor foo = 'Default';
148+
}
149+
```
137150

138-
When compiling JavaScript with **Babel**, you **may use class fields** for declaring reactive properties as long as you set `setPublicClassFields` to `true` in the `assumptions` config of your `babelrc`. Note, for older versions of Babel, you also need to include the plugin `@babel/plugin-proposal-class-properties`:
151+
For **TypeScript**, you **may use class fields** for declaring reactive properties as long as you use one of these patterns:
152+
* Set the `useDefineForClassFields` compiler option to `false`. This is already the recommendation when [using decorators with TypeScript](/docs/v3/components/decorators/#decorators-typescript).
153+
```json
154+
// tsconfig.json
155+
{
156+
"compilerOptions": {
157+
"experimentalDecorators": true, // If using decorators
158+
"useDefineForClassFields": false,
159+
}
160+
}
161+
```
162+
```ts
163+
class MyElement extends LitElement {
164+
static properties = {foo: {type: String}}
165+
foo = 'Default';
139166

140-
```js
141-
assumptions = {
142-
"setPublicClassFields": true
143-
};
167+
@property()
168+
bar = 'Default';
169+
}
170+
```
144171

145-
plugins = [
146-
["@babel/plugin-proposal-class-properties"],
147-
];
172+
* Add the `declare` keyword on the field, and put the field's initializer in the constructor.
173+
```ts
174+
class MyElement extends LitElement {
175+
declare foo: string;
176+
static properties = {foo: {type: String}}
177+
constructor() {
178+
super();
179+
this.foo = 'Default';
180+
}
181+
}
148182
```
149183

150-
For information about using class fields with **decorators**, see [Avoiding issues with class fields and decorators](/docs/v3/components/decorators/#avoiding-issues-with-class-fields).
184+
* Add the `accessor` keyword on the field to use [auto-accessors](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#auto-accessors-in-classes).
185+
```ts
186+
class MyElement extends LitElement {
187+
static properties = {foo: {type: String}}
188+
accessor foo = 'Default';
189+
190+
@property()
191+
accessor bar = 'Default';
192+
}
193+
```
151194

152195
### Property options
153196

0 commit comments

Comments
 (0)