TypeScript中React.PureComponent可选默认Props配置问题
当然可以给PureComponent设置可选props——你遇到的编译错误和Readonly无关,核心问题是组件的props接口和connect传递的props类型不匹配,另外你的接口里还有个小细节需要修正。
先修正接口里的类型错误
你的CounterProps里value?: string & number;这行有问题:string & number是never类型(没有值能同时是字符串和数字),应该改成你实际需要的类型,比如可选的数字:
interface CounterProps { incrementAsync(): void; increment(): void; decrement(): void; value?: number; // 改成可选数字,或者string | number如果需要支持两种类型 }
为什么connect会报错?
当你使用connect时,mapStateToProps返回的对象(比如{ value: number })和mapDispatchToProps返回的方法会合并成组件的props。如果mapStateToProps总是返回value(即value是必传的),但你的组件接口里value是可选的,TypeScript就会抛出类型不匹配的错误——这和PureComponent的Readonly属性无关,Readonly<P>只是禁止在组件内部修改props,完全允许存在可选键。
解决方案:让组件接口和connect提供的props匹配
根据你的业务场景,有两种处理方式:
方式1:如果value是必传的(mapStateToProps总是返回它)
直接把接口里的value改成必填项:
interface CounterProps { incrementAsync(): void; increment(): void; decrement(): void; value: number; // 去掉?,设为必填 }
方式2:如果value可能不存在,设置默认值
如果value可能从state里取不到,你可以在两个地方设置默认值:
- 在组件里设置defaultProps:PureComponent完全支持defaultProps
- 在mapStateToProps里处理默认值
示例代码如下:
import React from 'react'; import { connect } from 'react-redux'; // 修正后的接口 interface CounterProps { incrementAsync(): void; increment(): void; decrement(): void; value?: number; } class Counter extends React.PureComponent<CounterProps> { // 设置默认props static defaultProps: Partial<CounterProps> = { value: 0 }; render() { // 因为有defaultProps,这里可以安全地使用this.props.value return ( <div> <button onClick={this.props.incrementAsync}>Increment after 1 second</button>{' '} <button onClick={this.props.increment}>Increment</button>{' '} <button onClick={this.props.decrement}>Decrement</button> <hr /> <div>Clicked: {this.props.value} times</div> </div> ); } } // 假设你的state结构 interface AppState { counter: number; } // mapStateToProps里处理默认值(可选,和defaultProps二选一或者结合使用) const mapStateToProps = (state: AppState) => ({ value: state.counter ?? 0 // 如果state.counter不存在,返回0 }); // mapDispatchToProps示例 const mapDispatchToProps = { increment: () => ({ type: 'INCREMENT' }), decrement: () => ({ type: 'DECREMENT' }), incrementAsync: () => ({ type: 'INCREMENT_ASYNC' }) }; // 现在connect不会报错了 export default connect(mapStateToProps, mapDispatchToProps)(Counter);
关于Readonly的误区
PureComponent的props类型是Readonly<{ children?: ReactNode }> & Readonly<P>,这里的Readonly只是把props对象变成只读的,不允许你在组件内部修改this.props的属性,但完全支持可选属性。比如Readonly<{ value?: number }>是完全合法的类型,这不是你报错的原因。
内容的提问来源于stack exchange,提问作者Michał Wojas

