我正在尝试向旧组件添加类型注释,但不确定是否 connect
的类型支持我正在尝试做的事情。该组件是一个连接的组件,它接受一个广泛类型的 prop,然后使用该 prop 查找状态中的值,并吐出一个更窄的 prop。
目前,我可以用广泛的类型定义 Prop ,代码就可以工作了。但是,我在组件中编写的任何代码都必须符合这种广泛的类型,即使我知道它已经缩小了。因此,为了满足 typescript ,我要么必须添加类型断言,要么必须进行不必要的类型检查。
下面是一个简化的代码示例,用于显示该行为:
interface ExampleProps {
thing: string | number;
}
const Example extends React.Component<ExampleProps> {
render() {
const problem = this.props.thing * 2; // type error
// Workaround, but losing some typesafety
// const notAProblem = (this.props.thing as number) * 2;
// Workaround, but doing unnecessary checks
// if (typeof this.props.thing === 'number') {
// const notAProblem = this.props.thing * 2;
// }
return null;
}
}
const mapStateToProps = (state: RootState, otherProps: ExampleProps) => {
if (typeof otherProps.thing === 'string') {
return {
thing: state.lookup[otherProps.thing]; //resolves to a number
}
}
return {
thing, // also a number
}
}
export default connect(mapStateToProps)(Example)
在上面的代码中,typescript 正确地指出了 const problem: number = this.props.thing * 2;
是个问题。使用我定义的类型,this.props.thing
可能是一个字符串,所以它会正确给出错误 The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
是否可以使用 connect
以不同的 Prop 进来而不是出去的方式?换句话说,我需要有人能够渲染 <Example thing={2} />
或 <Example thing={"2"} />
,但要让示例中的代码知道这一点,多亏了 mapStateToProps,thing
只能是 number
最佳答案
方法 1:每个字段的通用类型
一种方法是使“事物”成为 ExampleProps
上的通用类型,即:
interface ExampleProps<T extends (string | number)> {
thing: T;
}
然后你可以分别在类和函数类型签名中指定不同的具体类型:
class Example extends Component<ExampleProps<number>> {
render() {
const problem: number = this.props.thing * 2;
return null;
}
}
const mapRootStateToExampleProps = (state: RootState, {thing}: ExampleProps<string | number>) => {
if (typeof thing === 'string') {
return {
thing: state.lookup[thing] //resolves to a number
}
}
return {
thing, // also a number
}
}
不过,这可能不是最佳解决方案,因为您的类型签名可能会很快变得冗长。它只对 ExampleProps 接口(interface)的一个或两个字段真正有意义。
方法 2:“out”参数的基础接口(interface),“in”参数扩展基础
另一种方法是声明一个表示传入 Prop 的基本接口(interface),然后声明一个扩展它的接口(interface)表示传出的 Prop - 然后您只需要指定在“传出”时修改的类型,这样您没有重复很多代码:
interface ExamplePropsIn {
thing: string | number;
other: string;
}
interface ExamplePropsOut extends ExamplePropsIn {
thing; number;
}
class Example extends Component<ExamplePropsOut> {
render() {
const problem: number = this.props.thing * 2;
return null;
}
}
const mapRootStateToExampleProps = (state: RootState, {thing}: ExamplePropsIn) => {
if (typeof thing === 'string') {
return {
thing: state.lookup[thing] //resolves to a number
}
}
return {
thing, // also a number
}
}
关于reactjs - mapStateToProps 可以缩小 props 的类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58241408/