Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

declaring a property in constructor with typescript react

From the draft-js documention, one can (in vanilla React, with no typescript) setup the Draft-js environment thus, noticing that the onChange property can be declared directly in the constructor:

import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';

class MyEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {editorState: EditorState.createEmpty()};
    this.onChange = (editorState) => this.setState({editorState});
  }
  render() {
    const {editorState} = this.state;
    return <Editor editorState={editorState} onChange={this.onChange} />;
  }
}

However, when I try to do the same with Typescript/React (code below), I get this error

error TS2339: Property 'onChange' does not exist on type 'Main'.

class Main extends React.Component<MainProps, MainState> {

    constructor(props) {
    super(props);
    this.state = { todos: [], editorState: EditorState.createEmpty() };
    this.onChange = (editorState) => this.setState({ editorState });
  }

I also tried adding onChange as a property to the props

interface MainProps {
    model: Model;
    onChange: Function;
}

What is the appropriate way to declare such a function property in typescript/react?

like image 620
Leahcim Avatar asked May 18 '16 14:05

Leahcim


People also ask

How do you write a constructor in TypeScript?

The TypeScript docs have a great example of constructor usage: class Greeter { greeting: string; constructor(message: string) { this. greeting = message; } greet() { return "Hello, " + this. greeting; } } let greeter = new Greeter("world");

Can you access props in constructor React?

props will be undefined in the constructor, which can lead to bugs. Typically, in React constructors are only used for two purposes: Initializing local state by assigning an object to this.

How do you define a property in React?

Data within React Components is stored as either properties or state. Properties are the input values to the component. They are used when rendering the component and initializing state (discussed shortly). After instantiating the component, properties should be considered immutable.

How do I create an instance of a class in TypeScript?

In the highlighted code, you added a parameter called name of type string to your class constructor. Then, when creating a new instance of the Person class, you are also setting the value of that parameter, in this case to the string "Jane" . Finally, you changed the console. log to print the argument to the screen.


3 Answers

Try this:

class Main extends React.Component<MainProps, MainState> {
    constructor(props) {
        super(props);
        this.state = { todos: [], editorState: EditorState.createEmpty() };
        this.onChange = (editorState) => this.setState({ editorState });
    }

    onChange: (state: MainState) => void;

}

I haven't tested it, but I think it should work.


Edit

Yeah, there's a problem there that I haven't noticed, it should be:

class Main extends React.Component<MainProps, MainState> {
    constructor(props) {
        super(props);

        this.state = { todos: [], editorState: EditorState.createEmpty() };
        this.onChange = (editorState) => this.setState({
            editorState: editorState
        } as MainState);
    }

    onChange: (state: MainState) => void;

}

The type assertion (as MainState) is needed if the todos property isn't optional, if it is optional (todos?: any[]) then there's no need for the assertion.

As for what seems to be duplication with the onChange definition, it is explained in short in the Mixins part of the typescript docs, but in your example the definition in the class:

onChange: (state: MainState) => void;

let's the compiler know that instances of Main have this method called onChange that receives a MainState and returns void.
But the implementation of this method is only assigned when the instance is created in the ctor:

this.onChange = (editorState) => this.setState({ editorState });

If the definition is missing then the assignment in the ctor will produce a compilation error: property 'onChange' does not exist on type 'Main'.

like image 100
Nitzan Tomer Avatar answered Oct 21 '22 13:10

Nitzan Tomer


You can use handleChange method like this :

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Editor, EditorState } from 'draft-js';

interface MyEditorProps {
}

class MyEditor extends React.Component<MyEditorProps, any> {
  constructor(props: MyEditorProps) {
    super(props);

    this.state = { editorState: EditorState.createEmpty() };
  }
  handleChange(e: EditorState) {
    this.setState({ editorState: e });
  }
  render() {
    return (
      <Editor editorState={this.state.editorState} onChange={e => this.handleChange(e)} />
    );
  }
}

ReactDOM.render(
  <MyEditor />,
  document.getElementById('editor'),
);

export { MyEditor }
like image 35
Karim Ben Yezza Avatar answered Oct 21 '22 15:10

Karim Ben Yezza


Alternatively, you can try it like this:

private onChange = (editorState) => this.setState({ editorState } as MainState)

just in the body of the class, where you define other class properties. I dunno, which version you're running, but this code totally works in ES2015 and TypeScript 2.0.10

like image 33
SMSk Avatar answered Oct 21 '22 15:10

SMSk