I am not able to figure out the type of my mapDispatchToProps. Check below in the SignInComponent const mapDispatchToProps
.
Seems simple as the functions takes signIn() as a parameter, from whom type I have availble. However I was not able to figure that out.
This is my autAction.ts:
import firebase from 'firebase/app'
import { Dispatch } from 'react';
type AuthAction = {
type: string,
err?: unknown
}
export const signIn = (credentials: {email:string, password:string}) => {
return (dispatch: Dispatch<AuthAction>) => {
firebase.auth().signInWithEmailAndPassword(
credentials.email,
credentials.password
).then(() => {
dispatch({ type: 'LOGIN_SUCCESS'})
}).catch((err) => {
dispatch({ type: 'LOGIN_ERROR', err})
});
}
}
And this is my SignIn component:
import React, { BaseSyntheticEvent, Component } from 'react'
import { connect } from 'react-redux';
import { signIn } from '../../store/actions/authActions';
type IConnectedDispatch = {
signIn: typeof signIn
}
interface IMyComponentProps {
signIn: (credentials: {email:string, password:string}) => void;
}
class SignIn extends Component<IMyComponentProps> {
state = {
email:'',
password:''
}
handleChange = (e:BaseSyntheticEvent) => {
this.setState({
[e.target.id]: e.target.value
});
}
handleSubmit = (e:BaseSyntheticEvent) => {
e.preventDefault();
//console.log(this.state);
this.props.signIn(this.state);
}
render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">Sing In</h5>
<div className="input-field">
<label htmlFor="email">Email</label>
<input type="email" id="email" onChange={this.handleChange}/>
</div>
<div className="input-field">
<label htmlFor="password">Password</label>
<input type="password" id="password" onChange={this.handleChange}/>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Login</button>
</div>
</form>
</div>
)
}
}
type AuthAction = {
type:string,
err?: unknown
}
const mapDispatchToProps = (dispatch: any): IConnectedDispatch => { //TYPE CHALLENGE HERE.
return {
signIn: (credentials:{ email:string, password:string}) => dispatch(signIn(credentials))
}
}
export default connect<React.FunctionComponent>(null,mapDispatchToProps)(SignIn)
As shown in @liamgbs' answer, your mapDispatchToProps
isn't really necessary, but I do want to answer your questions regarding the typescript issues.
mapDispatchToProps
is a function which takes dispatch
as an argument and returns a keyed object of props. So the type is essentially (dispatch: Dispatch)
.
The question is which Dispatch
definition to use here, as multiple packages have their own typings for it. The more basic definitions of Dispatch
from react
and redux
expect that dispatch
will only be called with a plain action object. The return value from your signIn
action creator is instead a function of dispatch
(a "thunk"). So you need to use typings from the redux-thunk
package.
{signIn: typeof signIn}
is also not quite right because you are calling signIn
rather than just returning it. The actual interface is your IMyComponentProps
, where signIn
is a void
function.
import { ThunkDispatch } from "redux-thunk";
interface LoginCredentials {
email: string;
password: string;
}
interface IMyComponentProps {
signIn: (credentials: LoginCredentials) => void;
}
const mapDispatchToProps = ( dispatch: ThunkDispatch<any, never, AuthAction> ): IMyComponentProps => {
return {
signIn: (credentials: LoginCredentials) => dispatch(signIn(credentials))
};
};
Annoyingly, ThunkDispatch
requires you to set all three generics. That first any
represents the type of your redux state, so you could replace that with an actual type if you want. The never
is the extra args in your action creator which you aren't using.