Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property 'blockId' has no initializer and is not definitely assigned in the constructor. #1273

Closed
andyjessop opened this issue Nov 21, 2023 · 5 comments · Fixed by #1274
Closed
Assignees

Comments

@andyjessop
Copy link

andyjessop commented Nov 21, 2023

Which package(s) are affected?

Lit Core (lit / lit-html / lit-element / reactive-element)

Description

I'm defining a property like this:

import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('rune-block-actions')
export class RuneBlockActions extends LitElement {
  @property()
  blockId: string;

I get this TS error in the editor:

Property 'blockId' has no initializer and is not definitely assigned in the constructor.

Reproduction

The code is unfortunately closed-source, and I cannot reproduce on the playground.

Workaround

I have not found a workaround.

Is this a regression?

No or unsure. This never worked, or I haven't tried before.

Affected versions

3.0.2

Browser/OS/Node environment

Browser: Chrome 119.0.6045.105
OS: Mac 14
Node: 18.6.1
npm: 9.5.1

@andyjessop andyjessop changed the title Property will not trigger updates as expected because it is set using class fields Property 'blockId' has no initializer and is not definitely assigned in the constructor. Nov 21, 2023
@andyjessop
Copy link
Author

andyjessop commented Nov 21, 2023

Some extra info. I have this in the tsconfig:

    "experimentalDecorators": true,
    "useDefineForClassFields": false,

And it's the same whether or not I add the options in the property({ type: String }) decorator.

@AndrewJakubowicz
Copy link
Contributor

The error "Property '...' has no initializer and is not definitely assigned in the constructor." is raised if you haven't initialized a property.

For example the following code:

class ExampleClass {
    name: string
//  ~~~~ Property 'name' has no initializer and is not definitely assigned in the constructor.
}

Repro in TypeScript playground

This can be fixed in a couple ways. The simplest way is to initialize blockId to an initial value. In your example maybe an empty string?

@customElement('rune-block-actions')
export class RuneBlockActions extends LitElement {
  @property()
  blockId = "";

If for some reason you have a reason to not initialize the property, you can opt-out of setting an initial value with ! (TypeScript playground sample).

class ExampleClass {
    // Don't do this unless you know what you are doing.
    // TypeScript now types `name` to be a string, but it'll be `undefined` if no one initializes it.
    name!: string
}

@andyjessop
Copy link
Author

The problem here is that the examples in the lit docs don't do any of what you described above. You need to set "strictPropertyInitialization": false in your tsconfig.json, and I don't see any mention of this in the docs. There is this section, but the recommended tsconfig properties are not sufficient to suppress the warnings. Here are some of the examples from the docs:

class MyElement extends LitElement {
  @property()
  name: string;
}
class MyElement extends LitElement {
  @property({type: String})
  mode: string;

I would say that the takeaway here is that there needs to be a prominent section on tsconfig, probably both in getting started, and in the properties section, and it should recommend:

"experimentalDecorators": true,
"useDefineForClassFields": false,
"strictPropertyInitialization": false

@AndrewJakubowicz
Copy link
Contributor

AndrewJakubowicz commented Nov 21, 2023

You raise a great point about our documentation. We definitely need to address that. Thank you for calling it out. The examples you've pulled from the documentation should be changed to:

class MyElement extends LitElement {
  @property()
  name?: string;
}

and

class MyElement extends LitElement {
  @property({type: String})
  mode?: string;

I wouldn't recommend globally changing "strictPropertyInitialization": false as that hinders the benefits of TypeScript, as the uninitialized property could be undefined. I'd lean towards either asserting with ! that you know it must be initialized, or use ? to declare that it may be undefined if uninitialized on a case by case basis. And assigning a default value when that makes sense.

What do you think about those proposed changes?

@andyjessop
Copy link
Author

I think that makes sense. Thanks very much for the clarification!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants