基于未定义的联合类型的 React Redux 编译错误
Compilation error with React Redux based on a union type with undefined
我目前正在做一个关于将 Redux 与 React 结合使用的教程,并决定使用 Typescript 来完成。我收到一个编译错误,其中我的商店的状态是 {posts: PostType[]} 类型。但是我收到一条错误消息说
Type '{ posts: PostType[]; } | undefined' is not assignable to type '{ posts: PostType[]; }'
我不确定该怎么做,因为在我自己的代码中我没有明确建议帖子可能未定义。以下是代码中的相关点。
// The component using redux
handleClick = () => {
const post = this.props.post! as PostType
this.props.deletePost(post.id)
}
const mapStateToProps = (state: {posts: PostType[]}, ownProps: Props) => {
return {
post: state.posts.find(post => {
return post.id === parseInt(ownProps.match.params.post_id);
})
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
deletePost: (id: number) => {dispatch({type: 'DELETE_POST', id: id})}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Post);
// The reducer
import { PostType } from "../components/Home";
const initState = {
posts: [{id: 1, title: 'Doctors hate him', body: 'Discover the new trick to stay young', userId: 3},
{id: 2, title: 'Fresh donuts', body: 'Hand-glazed', userId: 4},
{id: 3, title: 'Duque dimite', body: 'El presidente colobiano dio su renuncia', userId: 5}]
}
const rootReducer = (state: {posts: PostType[]} = initState, action: {type: string, id: number}) => {
if (action.type === 'DELETE_POST') {
return {
...state,
posts: state.posts.filter(post => post.id !== action.id)
}
}
}
export default rootReducer;
我注意到的一件奇怪的事情是,如果我从 rootReducer 函数中删除 if 语句,我的代码可以正常转换。我真的很困惑。我确实尝试研究这个问题,我发现了一些暗示它可能与 --strictNullChecks 标志与 redux 不兼容有关的东西,但我不确定。感谢您的帮助。
编辑:堆栈跟踪 + 下面的组件
Post.tsx:48 Uncaught TypeError: Cannot read property 'posts' of undefined
at Function.mapStateToProps [as mapToProps] (Post.tsx:48)
指的是这个
const mapStateToProps = (state: {posts: PostType[]} , ownProps: Props) => {
return {
post: state.posts.find(post => { // this line causes the error
return post.id === parseInt(ownProps.match.params.post_id);
})
}
}
虽然我认为上面的代码更相关,但我将在下面保留组件代码。
interface PostProps {
post_id: string
}
interface Props extends RouteComponentProps<PostProps> {
post?: PostType
deletePost: (id: number) => void
}
class Post extends Component<Props, {}> {
handleClick = () => {
const post = this.props.post! as PostType
this.props.deletePost(post.id)
}
render() {
let post;
if (this.props.post !== undefined) {
const postData = this.props.post! as PostType
post =
<div className="post">
<h4 className="center">{postData.title}</h4>
<p>{postData.body}</p>
<div className="center">
<button className="btn grey" onClick={this.handleClick}>Delete Post</button>
</div>
</div>;
} else {
post = <h4>Loading post...</h4>;
}
return (
<div className="container">
{post}
</div>
);
}
}
事实证明这是我的reducer 的错误。我之前检查了参数的 action.type,然后 returned 了一个新的状态,但是如果它不是那种类型,我 returned void 认为它很好,因为我没有在我的代码中传递任何其他类型的操作。实际上,reducer 在后台被调用,因此它导致了这个错误,因为现在状态是未定义的。所以总是 return 现有状态作为减速器中的默认值!
仅修复以下必要内容:
const rootReducer = (state: {posts: PostType[]} = initState, action: {type: string, id: number}) => {
if (action.type === 'DELETE_POST') {
return {
...state,
posts: state.posts.filter(post => post.id !== action.id)
}
}
return {
...state // We do this because the reducer is called by something that was not our dispatch
}
}
我目前正在做一个关于将 Redux 与 React 结合使用的教程,并决定使用 Typescript 来完成。我收到一个编译错误,其中我的商店的状态是 {posts: PostType[]} 类型。但是我收到一条错误消息说
Type '{ posts: PostType[]; } | undefined' is not assignable to type '{ posts: PostType[]; }'
我不确定该怎么做,因为在我自己的代码中我没有明确建议帖子可能未定义。以下是代码中的相关点。
// The component using redux
handleClick = () => {
const post = this.props.post! as PostType
this.props.deletePost(post.id)
}
const mapStateToProps = (state: {posts: PostType[]}, ownProps: Props) => {
return {
post: state.posts.find(post => {
return post.id === parseInt(ownProps.match.params.post_id);
})
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
deletePost: (id: number) => {dispatch({type: 'DELETE_POST', id: id})}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Post);
// The reducer
import { PostType } from "../components/Home";
const initState = {
posts: [{id: 1, title: 'Doctors hate him', body: 'Discover the new trick to stay young', userId: 3},
{id: 2, title: 'Fresh donuts', body: 'Hand-glazed', userId: 4},
{id: 3, title: 'Duque dimite', body: 'El presidente colobiano dio su renuncia', userId: 5}]
}
const rootReducer = (state: {posts: PostType[]} = initState, action: {type: string, id: number}) => {
if (action.type === 'DELETE_POST') {
return {
...state,
posts: state.posts.filter(post => post.id !== action.id)
}
}
}
export default rootReducer;
我注意到的一件奇怪的事情是,如果我从 rootReducer 函数中删除 if 语句,我的代码可以正常转换。我真的很困惑。我确实尝试研究这个问题,我发现了一些暗示它可能与 --strictNullChecks 标志与 redux 不兼容有关的东西,但我不确定。感谢您的帮助。
编辑:堆栈跟踪 + 下面的组件
Post.tsx:48 Uncaught TypeError: Cannot read property 'posts' of undefined
at Function.mapStateToProps [as mapToProps] (Post.tsx:48)
指的是这个
const mapStateToProps = (state: {posts: PostType[]} , ownProps: Props) => {
return {
post: state.posts.find(post => { // this line causes the error
return post.id === parseInt(ownProps.match.params.post_id);
})
}
}
虽然我认为上面的代码更相关,但我将在下面保留组件代码。
interface PostProps {
post_id: string
}
interface Props extends RouteComponentProps<PostProps> {
post?: PostType
deletePost: (id: number) => void
}
class Post extends Component<Props, {}> {
handleClick = () => {
const post = this.props.post! as PostType
this.props.deletePost(post.id)
}
render() {
let post;
if (this.props.post !== undefined) {
const postData = this.props.post! as PostType
post =
<div className="post">
<h4 className="center">{postData.title}</h4>
<p>{postData.body}</p>
<div className="center">
<button className="btn grey" onClick={this.handleClick}>Delete Post</button>
</div>
</div>;
} else {
post = <h4>Loading post...</h4>;
}
return (
<div className="container">
{post}
</div>
);
}
}
事实证明这是我的reducer 的错误。我之前检查了参数的 action.type,然后 returned 了一个新的状态,但是如果它不是那种类型,我 returned void 认为它很好,因为我没有在我的代码中传递任何其他类型的操作。实际上,reducer 在后台被调用,因此它导致了这个错误,因为现在状态是未定义的。所以总是 return 现有状态作为减速器中的默认值!
仅修复以下必要内容:
const rootReducer = (state: {posts: PostType[]} = initState, action: {type: string, id: number}) => {
if (action.type === 'DELETE_POST') {
return {
...state,
posts: state.posts.filter(post => post.id !== action.id)
}
}
return {
...state // We do this because the reducer is called by something that was not our dispatch
}
}