I'm attempting to add type annotations to an old component, and am not sure if connect's types support what i'm trying to do. The component is a connected component which takes in a prop with a broad type, then uses that prop to look up a value in state, and spits out a narrower prop.
At the moment, i can define the props with the broad type and the code will work. However, any code i write inside the component has to conform to this broad type, even though i know it has been narrowed. Thus to satisfy typescript i either have to add in type assertions, or unnecessary typechecks.
Here's a simplified example of the code to show the behavior:
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)
In the above code, typescript rightly points out that const problem: number = this.props.thing * 2; is a problem. With the types i've defined, this.props.thing might be a string, so it correctly gives the error The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
Is it possible to use connect in such a way that different props come in than go out? In other words, i need someone to be able to render <Example thing={2} /> or <Example thing={"2"} />, and yet for code inside the Example to know that, thanks to mapStateToProps, thing can only be a number