How to correctly set initial state in React with Typescript without constructor?

14,194

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.

Share:
14,194

Related videos on Youtube

John
Author by

John

Updated on June 04, 2022

Comments

  • John
    John almost 2 years

    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?

    • Estus Flask
      Estus Flask over 5 years
      @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).
  • John
    John over 5 years
    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 :)
  • Maksim Nesterenko
    Maksim Nesterenko over 3 years
    State is read-only in react types by default. No need to apply your own read-only on top.
  • rshepp
    rshepp over 3 years
    "No need to apply your own read-only on top." - incorrect. Without declaring state as readonly, the compiler will allow code that entirely replaces state, eg. this.state = { value: 10 };. And, without using the Readonly modifier, the compiler will allow code that improperly updates state members, eg. this.state.value = 10;. Try it yourself and you'll see without these modifiers the compiler won't protect you from doing the wrong thing.
  • Maksim Nesterenko
    Maksim Nesterenko over 3 years
    readonly state = {} is ok. Though Readonly is excess. See: github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types‌​/…