反应 redux 打字稿:连接缺少类型错误 [英] React redux typescript: connect has missing type error
问题描述
我正在尝试让 react-redux 应用程序与 typescript 一起运行,但我一直在围绕相同的错误盘旋.以下代码编译并产生预期结果
I am trying to get a react-redux app going with typescript, but I keep circling around the same error. The following code compiles and produces expected result
// State definition
interface HelloWorldState {
clickCount: number
}
interface AppState extends HelloWorldState {}
// Props definitions
interface HelloWorldProps {
count: number
}
// Actions
const CLICK = 'CLICK';
const click = () => {return {type:CLICK}};
// Reducers
function clickCount(state:number = 0, action:Action) {
if (typeof state === 'undefined') {
return 0;
}
switch (action.type) {
case CLICK:
return state + 1;
default:
return state;
}
}
let rootReducer = combineReducers({
clickCount
});
// Store
let store = createStore(rootReducer);
// Components
class HelloWorld extends React.Component<any, any> {
render() {
return <div onClick={this.handleClick.bind(this)}>Hello world "{this.props.count}"</div>
}
handleClick() {
store.dispatch(click())
}
}
// Container components
const mapStateToProps = (state:AppState):HelloWorldState => {
return Immutable.fromJS({
count: state.clickCount
})
};
const ConnectedHelloWorld = connect(
mapStateToProps
)(HelloWorld);
render(
<Provider store={store}>
<ConnectedHelloWorld/>
</Provider>,
container
);
太好了!但我使用的是 TypeScript,因为我想在编译时进行类型检查.类型检查最重要的是 state 和 props.所以我想做 class HelloWorld extends React.Component
而不是 class HelloWorld extends React.Component
.但是,当我这样做时,我从对 render
Great! But I am using TypeScript, because I want to get type checks at compile time. The most important thing to type check is state and props. So instead of class HelloWorld extends React.Component<any, any>
, I want to do class HelloWorld extends React.Component<HelloWorldProps, any>
. When I do this, however, I get the following compile error from the call to render
TS2324:Property 'count' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<HelloWorld> & HelloWorldProps & { children?: React...'.
我真的不明白为什么.count
IS 出现在 HelloWordProps
定义中,它是由 reducer 提供的,所以我应该没问题,对吧?类似的问题表明这是一个推理问题,我应该声明对 connect
的调用类型,但我似乎无法找出如何
I don't really understand why. count
IS present in the HelloWordProps
definition, and it is provided by the reducer, so I should be fine, right? Similar questions has suggested that it is an inference problem, and that I should declare the type of the call to connect
, but I can't seem to find out how
package.json
package.json
{
"name": "reacttsx",
"scripts": {
"build": "webpack"
},
"devDependencies": {
"ts-loader": "^1.3.3",
"typescript": "^2.1.5",
"webpack": "^1.14.0",
"typings": "^2.1.0"
},
"dependencies": {
"es6-promise": "^4.0.5",
"flux": "^3.1.2",
"immutable": "^3.8.1",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.1.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.2",
"redux": "^3.6.0",
"redux-logger": "^2.7.4",
"redux-thunk": "^2.2.0"
}
}
typings.json
typings.json
{
"dependencies": {
"flux": "registry:npm/flux#2.1.1+20160601175240",
"immutable": "registry:npm/immutable#3.7.6+20160411060006",
"react": "registry:npm/react#15.0.1+20170104200836",
"react-dom": "registry:npm/react-dom#15.0.1+20160826174104",
"react-redux": "registry:npm/react-redux#4.4.0+20160614222153",
"redux-logger": "registry:dt/redux-logger#2.6.0+20160726205300",
"redux-thunk": "registry:npm/redux-thunk#2.0.0+20160525185520"
},
"globalDependencies": {
"es6-promise": "registry:dt/es6-promise#0.0.0+20160726191732",
"isomorphic-fetch": "registry:dt/isomorphic-fetch#0.0.0+20170120045107",
"jquery": "registry:dt/jquery#1.10.0+20170104155652",
"redux": "registry:dt/redux#3.5.2+20160703092728",
"redux-thunk": "registry:dt/redux-thunk#2.1.0+20160703120921"
}
}
更新
因为它抱怨 count
丢失,我尝试更新到
Since it was complaining that count
was missing, I tried updating to
render(
<Provider store={store}>
<ConnectedHelloWorld count={0}/>
</Provider>,
container
);
这解决了问题.所以问题是编译器不知道 Provider
正在提供计数.提供者使用商店.商店应该有 clickCount
值,该值由容器组件映射到 count
.
This solves the issue. So the issue is that the compiler doesn't know that the Provider
is providing the count. Provider uses the store. The store should have the clickCount
value which is mapped to count
by the container component.
我注意到我忘记了商店的初始状态.因此,即使类型已检出,状态也会为空.我更新为
I noticed I'd forgotten an initial state for the store. So even if the types had checked out, the state would be empty. I updated it to
// Store
let initialState:AppState = {clickCount: 0};
let store = createStore(rootReducer, initialState);
现在我确定 clickCount
在商店中设置正确.所以我希望 mapStateToProps
函数采用 AppState
并返回指定的 HelloWorldProps
,然后返回 Provider
应提供计数值.这是真的,但编译器没有看到.
Now I am certain that clickCount
is set properly in the store. So I'd expect the mapStateToProps
function to take the AppState
and return the HelloWorldProps
as specified, and then the Provider
should provide the count value. This is true, but the compiler does not see it.
那么如何补救呢?
推荐答案
这就是我在 Typescript Redux 应用程序中的做法(已根据您的代码进行调整但未经过测试)
This how I do it in a Typescript Redux App (adjusted to your code but not tested)
在下方评论编辑
输入
connect
和连接组件的 props (ConnectedHelloWorldProps
)
type
connect
with props for the Connected Component (ConnectedHelloWorldProps
)
const ConnectedHelloWorld:React.ComponentClass<ConnectedHelloWorldProps> =
connect<any,any,HelloWorldProps>(mapStateToProps)(HelloWorld)
interface ConnectedHelloWorldProps { }
interface HelloWorldProps extends ConnectedHelloWorldProps {
count: number
....
}
在Provider
<Provider store={store}>
<ConnectedHelloWorld/>
</Provider>
注意:这适用于这些类型
Note: this works fine with these typings
"@types/react": "^0.14.52",
"@types/react-dom": "^0.14.19",
"@types/react-redux": "^4.4.35",
"@types/redux-thunk": "^2.1.32",
ConnectedHellowWorldProps
这里并不真正需要,因为它是一个空接口,但在现实世界的场景中它可能包含一些道具.
ConnectedHellowWorldProps
is not really needed here, since it is an empty interface, but in a real world scenario it is likely to contain a few props.
基本原理是这样的:ConnectedHelloWorldProps
包含需要在 Provider 级别传递的内容.在 mapStateToProps
和/或 mapDispatchToProps
中,用任何需要的东西丰富实际的组件 HelloWorldProps
The basic principle is this: ConnectedHelloWorldProps
contain what needs to be passed at the Provider level. In mapStateToProps
and/or mapDispatchToProps
, enrich the actual Component HelloWorldProps
with whatever is needed
Redux Typescript 类型是一种野兽,但上面显示的应该足够了.
Redux Typescript typings are a beast but what is shown above should be sufficient.
export declare function connect<TStateProps, TDispatchProps, TOwnProps>(
mapStateToProps: FuncOrSelf<MapStateToProps<TStateProps, TOwnProps>>,
mapDispatchToProps?: FuncOrSelf<MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | MapDispatchToPropsObject>): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>;
interface ComponentDecorator<TOriginalProps, TOwnProps> {
(component: ComponentClass<TOriginalProps> | StatelessComponent<TOriginalProps>): ComponentClass<TOwnProps>;
}
这篇关于反应 redux 打字稿:连接缺少类型错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!