reactjs - InteliJ:Typescript 根据接口自动检查 {} 对象?
问题描述
这是错误连接到 Redux 的 React 组件的示例违规代码。
import React from 'react';
import { View, StyleSheet, ViewStyle, Text } from 'react-native';
import { connect } from "react-redux";
import { StoreState } from "../../store/storeState/storeState";
import { LogFactory, Logger } from "../../vlabs-js/general/logging/log";
interface DevCompProps {
counter: number
}
class UnconnectedDevComp extends React.Component<DevCompProps> {
private logger: Logger;
constructor(props: DevCompProps) {
super(props);
this.logger = LogFactory.fromComp('DevComp');
}
render() {
this.logger.info(`render(): props='${this.props.counter}'`);
return <View style={{flexDirection: 'row', borderWidth: 3, borderColor: 'black', padding: 5}}>
<Text>Counter:</Text>
<Text>{this.props.counter}</Text>
</View>
}
}
const mapStateToProps = (state: StoreState) => {
return {
number: state.devState.counter
};
};
export const DevComp = connect(mapStateToProps)(UnconnectedDevComp)
为了使代码正常工作,mapStateToProps 应该是
const mapStateToProps = (state: StoreState) => {
return {
counter: state.devState.counter
};
};
代替
const mapStateToProps = (state: StoreState) => {
return {
number: state.devState.counter
};
};
有没有办法编译/InteliJ-Warn 检查 mapStateToProps 返回的对象是否与接口匹配
interface DevCompProps {
counter: number
}
所以这样的错误会被 IDE 标记出来,而不必手动发现。
解决方案
简短的回答是“不”,因为这里的所有解决方案都很糟糕。处理函数组件和useSelector
钩子可能会更好。
当您使用错误的键进行映射时,您的组合DevComp
将是一个组件,counter
当您调用它时需要传入一个道具,以便打字稿正确地获取该部分。
您可以通过在函数上设置一些泛型来引发错误connect
,但这似乎很痛苦。我们要设置的变量是第一个,它是从 返回的 props mapStateToProps
,第三个是你希望调用组件的 props。
const DevComp = connect<DevCompProps, {}, {}>(mapStateToProps)(UnconnectedDevComp)
mapStateToProps
同样,您可以通过将返回类型设置为来引发错误Partial<DevCompProps>
。
您需要覆盖react-redux
包中的某些类型才能自动获得该推断。但这也很糟糕。
我们想让它返回的 propsmapStateToProps
不能包含组件 props 中不存在的任何键。
你不能通过操纵MapStateToProps
类型来做到这一点。这有三个变量,但没有一个代表要映射的组件的类型。你需要的是TStateProps
被限制。
export type MapStateToProps<TStateProps, TOwnProps, State = DefaultRootState> =
(state: State, ownProps: TOwnProps) => TStateProps;
connect
归根结底,问题在于HOC的两步性质。“连接器”的创建与将其应用于组件是分开的,因此连接器不能依赖于该组件。
这样做完全没问题:
const myWrapper = connect(mapStateToProps);
并获取类型
InferableComponentEnhancerWithProps<{ number: number; } & DispatchProp<AnyAction>, {}>
myWrapper
是一个可以包装任何组件并为其添加道具的函数number
。它不知道要应用的组件类型,也不关心该组件是否真的需要 prop number
。
您需要定义自己的函数,将这两个步骤组合成一个带有两个参数的函数,以便参数可以相互推断类型。我没有完整的解决方案。 connect
有 15 个不同的重载,这个类型签名只描述了一个。此外,实现是一个错误,但函数类型可以满足您的需求。
const myConnect = <InnerProps, MappedProps extends Partial<InnerProps> , State = DefaultRootState>(
mapStateToProps: (state: State) => MappedProps, Component: ComponentType<InnerProps>
): ComponentType<Omit<InnerProps, keyof MappedProps>> => {
return connect(mapStateToProps)(Component);
}
export const DevComp = myConnect(mapStateToProps, UnconnectedDevComp)
推荐阅读
- python - ModuleNotFoundError:在 pip install pyserial 之后没有名为“serial”的模块
- javascript - 如何在 Angular 中为原生元素添加多种样式
- docker - 在 Linux 上使用 confluent-kafka-go 构建 Go 应用程序
- angular - Angular - 如何从ngrx获取状态然后执行http
- doctrine - Zend Framework 2 - Doctrine - 迭代所有实体类
- javascript - 如何计算动态表中的复选框数
- azure - Azure 中的 Cassandra CPU 不平衡
- docker - 使用 Redis 作为 Docker 容器之间的链接
- r - 计划对比的 Tuckey 校正与 R 中的 emmeans 和 pairs()
- java - PHP不返回预期结果