我试图让react-redux应用程序与打字稿一起使用,但我仍然围绕同样的错误盘旋 . 以下代码编译并生成预期结果
// 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,因为我想在编译时进行类型检查 . 键入检查最重要的是状态和道具 . 所以不是 class HelloWorld extends React.Component<any, any>
,而是想做 class HelloWorld extends React.Component<HelloWorldProps, any>
. 但是,当我这样做时,我从调用 render
得到以下编译错误
TS2324:Property 'count' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<HelloWorld> & HelloWorldProps & { children?: React...'.
我真的不明白为什么 . count
IS 出现在 HelloWordProps
定义中,它由reducer提供,所以我应该没事,对吧?类似的问题表明它是一个推理问题,我应该声明 connect
的调用类型,但我似乎无法找出如何
的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
{
"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"
}
}
UPDATE
由于抱怨 count
缺失,我尝试更新到
render(
<Provider store={store}>
<ConnectedHelloWorld count={0}/>
</Provider>,
container
);
这解决了这个问题 . 所以问题是编译器不知道 Provider
正在提供计数 . 提供商使用商店 . 商店应具有 clickCount
值,该值由容器组件映射到 count
.
我注意到我忘记了商店的初始状态 . 所以即使类型已经签出,状态也是空的 . 我把它更新为
// Store
let initialState:AppState = {clickCount: 0};
let store = createStore(rootReducer, initialState);
现在我确定 clickCount
已在商店中正确设置 . 所以我希望 mapStateToProps
函数取 AppState
并按指定返回 HelloWorldProps
,然后 Provider
应该提供计数值 . 这是事实,但编译器没有看到它 .
那么如何解决这个问题呢?
2 回答
你的问题是
HelloWorldState
是这样定义的你要从
mapStateToProps
返回的道具是但是您将返回类型覆盖为
HelloWorldState
,因此返回类型不包含count
但clickCount
.fromJS打破了类型安全
ImmutableJS.fromJS
使用TypeScript类型推断非常糟糕:这里
state
的类型为any
,因此在将其指定为HelloWorldState
类型的返回值时,您没有任何错误 .mapStateToProps应该返回一个简单的对象
mapStateToProps
可以返回一个简单的对象,因为您不会直接从组件中编辑此状态:在这里,您将遇到使用ImmutableJS时没有的错误,告诉您无法将
{ count: number }
分配给{ clickCount: number }
.因此,只需删除返回类型,类型推断即可完成工作,或添加正确的类型 .
与Monolite的静态类型树结构共享
我还建议你使用Monolite这是一组用TypeScript编写的简单函数,用于Redux状态 .
它还允许您使用简单的JavaScript对象定义您的状态,并通过简单的函数对状态进行更新 .
P.S. 我是Monolite的作者
这是我如何在Typescript Redux App中进行的(根据您的代码调整但未经过测试)
edited with comment below
connect
,其中包含连接组件的道具(ConnectedHelloWorldProps
)Provider
中连接的组件及其ConnectedHelloWorldProps
道具注意:这适用于这些类型
这里并不真正需要
ConnectedHellowWorldProps
,因为它是一个空接口,但在现实世界中它可能包含一些道具 .基本原则是:
ConnectedHelloWorldProps
包含需要在提供者级别传递的内容 . 在mapStateToProps
和/或mapDispatchToProps
中,使用所需的任何内容丰富实际的组件HelloWorldProps
Redux Typescript类型是一种野兽,但上面所示的内容应该足够了 .