14

In modern JS, we can directly set an initial state for a React component like this:

class App extends React.Component {
  state = {value: 10}

  render() {
    return <div>{this.state.value}</div>
  }
}

When I am trying to do this with Typescript, TSLint says "The class property 'state' must be marked either 'private', 'public', or 'protected'". If I set it to "private", the linter will report Class 'App' incorrectly extends base class 'Component<{}, { value: number; }, any>'. Property 'state' is private in type 'App' but not in type 'Component<{}, { value: number; }, any>'. on App. I am aware that I can tweak the linter rules to skip this kind of checks, but checking the visibility of class properties in general is a good thing I want to utilize.

After testing out all three options, only choosing "public" won't get TSLint throw out errors. But since the state here represents the internal state of this specific component, setting it to public seems pretty weird. Am I doing it the correct way?

class App extends React.Component<{}, { value: number }> {
  public state = { value: 10 };

  public render() {
    return <div>{this.state.value}</div>;
  }
}

In all TS-React tutorials I've found online, a constructor is used, like in the old JS syntax.

class App extends React.Component<{}, { value: number }> {
  constructor(props: any) {
    super(props);
    this.state = { value: 10 };
  }

  public render() {
    return <div>{this.state.value}</div>;
  }
}

Is setting class property directly considered a bad practice/style in Typescript?

7
  • I generally avoid using the constructor since it's not needed for setting properties (not needed in modern JavaScript anymore either). I don't see it being bad practice / bad style. If you don't specify the keyword public, it would automatically be public. You can use private if you want since you won't be using the state outside of the class anyway, but ultimately it doesn't matter much. Commented Oct 10, 2018 at 20:49
  • Yes, I also avoid using the constructor when writing JS. In this case, if I use private, TSlint will report Class 'App' incorrectly extends base class 'Component<{}, { value: number; }, any>'. Property 'state' is private in type 'App' but not in type 'Component<{}, { value: number; }, any>'. on App. I am aware that I can configure TSlint to hide this kind of checks, but checking the visibility of class properties in general is a good thing I want to utilize. Commented Oct 10, 2018 at 20:55
  • See stackoverflow.com/a/52688791/3731501 . In all tutorials I've found online, a constructor is used, like in old JS syntax - persons who write tutorials aren't necessarily proficient in things they write about. TSlint says "The class property 'state' must be marked either 'private', 'public', or 'protected'". If I use private, TSlint will report - disable this rule, public is redundant. state shouldn't be private. Commented Oct 10, 2018 at 21:20
  • "setting it to public seems pretty weird". It's public in Component and that's that. It's not something to worry about. Commented Oct 10, 2018 at 21:26
  • 1
    @cartant OP states that first snippet produces linter error. This suggests that there's lint rule to specify the visibility explicitly (I didn't ever notice such rule because it seems to be useless). Commented Oct 10, 2018 at 22:11

3 Answers 3

23

Am I doing it the correct way?

Yes.

Is setting class property directly considered a bad style in Typescript?

No.

A slightly better approach

Consider declaring state as public readonly, and using the Readonly modifier.

This will satisfy TSLint while also giving you some protection against being modified incorrectly (ie. not using this.setState). Even though state is still exposed to the outside, this is never usually a problem.

interface IState {
  value: number;
}

class App extends React.Component<{}, IState> {
  public readonly state: Readonly<IState> = {
    value: 10
  }

  public render() {
    return <div>{this.state.value}</div>
  }
}

The TSLint rule

Declaring access modifiers explicitly is a good thing, even if it results in the same access implicitly. It helps keep your code clear, so I wouldn't disable this TSLint rule.

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

2 Comments

State is read-only in react types by default. No need to apply your own read-only on top.
readonly state = {} is ok. Though Readonly is excess. See: github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/…
-1

I'd say that setting the state property of a React component directly is poor practice unless you annotate the type to be the same as the state type parameter to React.Component. Without the annotation, TypeScript determines the type of this.state from the initializer, overriding the type from the superclass (which is based on the state type parameter) and won't give you an error if the type from the initializer comes out to be a subtype of the type parameter. This can cause unsoundness or unexpected behavior later; see this thread for an example.

1 Comment

Yes I agree. I looked into the type definitions of React.Component, state seems to be not annotated, so public here should be the right keyword to use indeed :)
-1

The state is immutable. The recommended way to set the initial state is by the constructor.

Note that 'state' is already defined and inherited so there is no need to re-declare it:

interface AppState {
    charge : number;
    spin   : number;
    color  : string;
}

interface AppProps {}

class App extends React.Component<AppProps, AppState> {

    constructor(props) {
        super(props);
        this.state={ charge: 0, spin: -0.5, color:'red' }; 
    }
}

BTW, This is exactly how it is defined in the react documentations:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.