Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript React State without Props

I'd like to take advantage of the static and strong typing in TypeScript, but only for the state since I don't intend to take in any props.

When I attempt to pass the interface as such, I end up with an error:

import * as React from 'react';
import {Link} from 'react-router-dom';
import Constants from '../Constants';

interface ILoginState {
   email: string;
   password: string;
   remember: boolean;
   error: string;
   isLoading: boolean;
}

class LoginView extends React.Component<{}, ILoginState> {

   constructor(props) {
      super(props);

      this.state = {
         email: '',
         password: '',
         remember: false,
         error: '',
         isLoading: false
      };
   }

 render() {
      return (<div>Login goes here</div>
      );
   }
}

export default LoginView;

I end up with a compile error:

ERROR in [at-loader] ./src/scripts/pages/LoginView.tsx:41:21 
    TS2345: Argument of type '{ [x: number]: any; }' is not assignable to parameter of type 'ILoginState | ((prevState: Readonly<ILoginState>, props: {}) => ILoginState | Pick<ILoginState, "...'.
  Type '{ [x: number]: any; }' is not assignable to type 'Pick<ILoginState, "email" | "password" | "remember" | "error" | "isLoading">'.
    Property 'email' is missing in type '{ [x: number]: any; }'.

I've also tried using 'any' in place of the empty brackets but that doesn't work either.

Here's the line 41 (this.SetState...) that the trace is referring to:

   handleChange = event => {
      const target = event.target;
      const value = target.type === 'checkbox' ? target.checked : target.value;
      this.setState({
         [target.name]: value
      });
   }

Here are all examples where that's used:

<input name="email" type="email" value={this.state.email} onChange={this.handleChange} />
<input name="password" type="password" value={this.state.password} onChange={this.handleChange} />
<input name="remember" type="checkbox" checked={this.state.remember} onChange={this.handleChange} />
like image 214
Seth Killian Avatar asked Jun 04 '18 23:06

Seth Killian


People also ask

How do I declare a state in TypeScript?

To use state in functional component use useState hook. This hook returns a tuple of two values. The first one is the current value of the state, the second one is a function to update the state. // into useState as an argument.

How do you use states in TypeScript React?

To type the useState hook as an object in React, use the hook's generic, e.g. const [employee, setEmployee] = useState<{name: string; salary: number}>({name: '',salary: 0}) . The state variable will only accept key-value pairs of the specified type.

When would you use state instead of props?

For parent-child communication, simply pass props. Use state to store the data your current page needs in your controller-view. Use props to pass data & event handlers down to your child components. These lists should help guide you when working with data in your components.

Should you use React FC?

You should probably not. The consensus in the React community now seems to be that, you should avoid using React. FC because it causes the component to implicitly take children . This means the component will accept children, even if they're not supposed to.


1 Answers

Option 1

class LoginView extends React.Component<{}, ILoginState> {
   constructor({}) {
   }
}

Option 2

class LoginView extends React.Component<null, ILoginState> {
   constructor(null) {
   }
}

Since props default value is an empty object, I personally prefer option 1.

Edit: it appears latest typescript versions do not support option 1. I'll suggest one of the following methods (tested on TS 3.7):

class LoginView extends React.Component<{}, ILoginState> {
   constructor() {
       super({});
   }
}

// OR
class LoginView extends React.Component<{}, ILoginState> {
   constructor(props = {}) {
       super(props);
   }
}

Thanks to @Andy who brought this update to my attention.

like image 136
yuval.bl Avatar answered Oct 19 '22 16:10

yuval.bl