我创建了一个说明性组件Hello
,我尝试在使用React-Redux的props
装饰器时使用state
和connect
的正确类型。
您可以在我创建的GitHub repository中进行游戏来说明这一点。
当connect
不用作装饰器,而是使用export default connect(mapStateToProps, mapDispatchToProps)(Hello)
而组件本身未导出时,这可行。
type HelloStateProps = { enthusiasmLevel: number; };
type HelloDispatchProps = { incrementEnthusiasm: () => void; decrementEnthusiasm: () => void; };
type HelloOwnProps = { name: string; };
type HelloProps = HelloStateProps & HelloDispatchProps & HelloOwnProps;
type HelloState = { useHi: boolean; };
// I am getting an error here
@connect(mapStateToProps, mapDispatchToProps)
export default class Hello extends React.Component<HelloProps, HelloState> {
state: HelloState = { useHi: false };
onChangeGreetingButtonClick: React.MouseEventHandler<HTMLButtonElement> = event =>
this.setState(state => ({ useHi: !state.useHi }))
render() {
const { useHi } = this.state;
const { name, enthusiasmLevel } = this.props;
return (
<div className="hello">
{useHi ? 'Hi' : 'Hello'} {name} x{enthusiasmLevel}
<div>
<button onClick={this.props.decrementEnthusiasm}>-</button>
<button onClick={this.props.incrementEnthusiasm}>+</button>
<button onClick={this.onChangeGreetingButtonClick}>Change greeting</button>
</div>
</div>
);
}
}
export function mapStateToProps({ enthusiasmLevel }: StoreState): HelloStateProps {
return { enthusiasmLevel };
}
export function mapDispatchToProps(dispatch: Dispatch<EnthusiasmAction>): HelloDispatchProps {
return Redux.bindActionCreators({ incrementEnthusiasm, decrementEnthusiasm }, dispatch);
}
尝试使用connect
作为装饰器时遇到的错误如下:
Unable to resolve signature of class decorator when called as an expression.
Type 'ComponentClass<Pick<HelloProps, "name">> & { WrappedComponent: ComponentType<HelloProps>; }' is not assignable to type 'typeof Hello'.
Type 'Component<Pick<HelloProps, "name">, ComponentState>' is not assignable to type 'Hello'.
Types of property 'state' are incompatible.
Type 'Readonly<ComponentState>' is not assignable to type 'HelloState'.
Property 'useHi' is missing in type 'Readonly<ComponentState>'.
当我完全剥离状态组件时,如下所示:
@connect(mapStateToProps, mapDispatchToProps)
export default class Hello extends React.Component<HelloProps> {
render() {
const { name, enthusiasmLevel } = this.props;
return (
<div className="hello">
Hi {name} x{enthusiasmLevel}
<div>
<button onClick={this.props.decrementEnthusiasm}>-</button>
<button onClick={this.props.incrementEnthusiasm}>+</button>
</div>
</div>
);
}
}
...我得到了这个错误:
Unable to resolve signature of class decorator when called as an expression.
Type 'ComponentClass<Pick<HelloProps, "name">> & { WrappedComponent: ComponentType<HelloProps>; }' is not assignable to type 'typeof Hello'.
Type 'Component<Pick<HelloProps, "name">, ComponentState>' is not assignable to type 'Hello'.
Types of property 'render' are incompatible.
Type '() => string | number | false | Element | Element[] | ReactPortal | null' is not assignable to type '() => Element'.
Type 'string | number | false | Element | Element[] | ReactPortal | null' is not assignable to type 'Element'.
Type 'null' is not assignable to type 'Element'.
问题出在哪里?我不明白错误信息。
在有状态的state
中,connect
应与useHi
产生差异,对吧?那为什么甚至报道呢? ReadOnly<HelloState>
中肯定不会遗漏ComponentState
,但render
来自哪里?
在无状态的JSX.Element
中,当悬停时,会显示null
返回类型。那么 <div class="form-group" id="assignto" style="display:none;">
<label class="control-label">Assigned To<span style="color:red;">*</span></label>
<select class="form-control boxed" name="assignedto" id="assignedto" required>
<option value="">Select</option>
<option value="Male">Male</option>
<option value="FeMale">FeMale</option>
</select>
</div>
是什么呢?
答案 0 :(得分:6)
答案 1 :(得分:1)
更高的Component Interface声明完成了将连接Type与组件状态和props Type结合起来的技巧。
connect.ts
import * as React from "react";
import {
connect as originalConnect,
MapStateToPropsParam,
MergeProps,
Options
} from "react-redux";
import { IState } from "./index";
export interface IDisPatchProps {
[key: string]: () => void;
}
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
TComponent extends React.ComponentType<TInjectedProps & TNeedsProps>
>(
component: TComponent
) => TComponent;
export interface IConnectProps {
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, IState>,
mapDispatchToProps?: IDisPatchProps
): InferableComponentEnhancerWithProps<
TStateProps & TDispatchProps,
TOwnProps
>;
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}>(
mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, IState>,
mapDispatchToProps?: IDisPatchProps,
mergeProps?: MergeProps<
TStateProps,
TDispatchProps,
TOwnProps,
TMergedProps
>,
options?: Options<TStateProps, TOwnProps, TMergedProps>
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
}
declare module "react-redux" {
// tslint:disable-next-line
interface Connect extends IConnectProps {}
}
export const connect = originalConnect as IConnectProps;
***ClassFile***
@connect(
(state: IState): IStateProps => ({
count: state.counter.count,
isLoading: state.counter.isLoading
}),
{
decrement,
increment
}
)
export default class MyApp
贷方转到: TomasHubelbauer https://github.com/TomasHubelbauer