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} />
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With