问题 TypeScript与Redux容器竞争
我在弄清楚如何正确打字时遇到了一些麻烦 Redux容器。
考虑一个简单的表示组件,可能如下所示:
interface MyProps {
name: string;
selected: boolean;
onSelect: (name: string) => void;
}
class MyComponent extends React.Component<MyProps, {}> { }
从这个组件的角度来看,所有道具都是必需的。
现在我想写一个容器,将所有这些道具拉出状态:
function mapStateToProps(state: MyState) {
return {
name: state.my.name,
selected: state.my.selected
};
}
function mapDispatchToProps(dispatch: IDispatch) {
return {
onSelect(name: string) {
dispatch(mySelectAction(name));
}
};
}
const MyContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
这有效,但有一个很大的打字问题:映射功能(mapStateToProps
和 mapDispatchToProps
)没有保护他们提供正确的数据来履行 MyProps
。这容易出错,拼写错误和重构不佳。
我可以使映射函数返回类型 MyProps
:
function mapStateToProps(state: MyState): MyProps { }
function mapDispatchToProps(dispatch: IDispatch): MyProps { }
然而,除非我全力以赴,否则这不起作用 MyProp
props可选,这样每个映射函数只能返回它们关心的部分。我不想让道具成为可选的,因为它们不是演示组件的可选项。
另一种选择是为每个地图功能拆分道具,并将它们组合成组件道具:
// MyComponent
interface MyStateProps {
name: string;
selected: boolean;
}
interface MyDispatchProps {
onSelect: (name: string) => void;
}
type MyProps = MyStateProps & MyDispatchProps;
class MyComponent extends React.Component<MyProps, {}> { }
// MyContainer
function mapStateToProps(state: MyState): MyStateProps { }
function mapDispatchToProps(dispatch: IDispatch): MyDispatchProps { }
好吧,这让我更接近我想要的东西,但它有点嘈杂,它让我在容器的形状周围写出我的演示组件道具界面,我不喜欢。
现在又出现了第二个问题。如果我想将容器放在另一个组件中,该怎么办:
<MyContainer />
这给出了编译错误 name
, selected
,和 onSelect
都缺失了...但这是故意的,因为容器连接到Redux并提供这些。所以这促使我回到使所有组件道具可选,但我不喜欢它,因为它们不是真正可选的。
事情变得更糟 MyContainer
有一些自己想要传递的道具:
<MyContainer section="somethng" />
现在我要做的就是拥有 section
一个必需的支柱 MyContainer
但不是支柱 MyComponent
,和 name
, selected
,和 onSelect
是必需的道具 MyComponent
但可选或不是道具 MyContainer
。我完全不知道如何表达这一点。
任何指导都将不胜感激!
12660
2017-11-18 07:58
起源
答案:
你的最后一个例子是正确的。你还需要定义的是一个 MyOwnProps
界面,并键入 connect
功能。
有了这些类型: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/react-redux/react-redux.d.ts,你可以做这样的事情
interface MyProps {
section: string;
name: string;
selected: boolean;
onSelect: (name: string) => void;
}
interface MyStateProps {
name: string;
selected: boolean;
}
interface MyDispatchProps {
onSelect: (name: string) => void;
}
interface MyOwnProps {
section: string;
}
class MyComponent extends React.Component<MyProps, {}> { }
function mapStateToProps(state: MyState): MyStateProps { }
function mapDispatchToProps(dispatch: IDispatch): MyDispatchProps { }
const MyContainer = connect<MyStateProps, MyDispatchProps, MyOwnProps>(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
这也让你输入 ownProps
在 mapStateToProps
和 mapDispatchToProps
,例如
function mapStateToProps(state: MyState, ownProps: MyOwnProps): MyStateProps
只要定义dispatch,state和ownProps类型,就不需要为MyProps类型定义交集类型。这样,您可以将MyProps保留在自己的位置,让容器或组件在没有容器的地方使用,根据需要应用道具。我想这取决于你和你的用例 - 如果你定义的话 MyProps = MyStateProps & MyDispatchProps & MyOwnProps
,它与一个特定的容器绑在一起,这个容器灵活性较差(但不那么冗长)。
作为一个解决方案,它非常冗长,但我认为没有办法告诉TypeScript不同的所需道具将在不同的地方组装,并且 connect
将他们绑在一起。
此外,为了它的价值,我通常选择道具,为了简单起见,所以我没有太多的经验来分享使用这种方法。
12
2017-11-18 15:44
答案:
你的最后一个例子是正确的。你还需要定义的是一个 MyOwnProps
界面,并键入 connect
功能。
有了这些类型: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/react-redux/react-redux.d.ts,你可以做这样的事情
interface MyProps {
section: string;
name: string;
selected: boolean;
onSelect: (name: string) => void;
}
interface MyStateProps {
name: string;
selected: boolean;
}
interface MyDispatchProps {
onSelect: (name: string) => void;
}
interface MyOwnProps {
section: string;
}
class MyComponent extends React.Component<MyProps, {}> { }
function mapStateToProps(state: MyState): MyStateProps { }
function mapDispatchToProps(dispatch: IDispatch): MyDispatchProps { }
const MyContainer = connect<MyStateProps, MyDispatchProps, MyOwnProps>(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
这也让你输入 ownProps
在 mapStateToProps
和 mapDispatchToProps
,例如
function mapStateToProps(state: MyState, ownProps: MyOwnProps): MyStateProps
只要定义dispatch,state和ownProps类型,就不需要为MyProps类型定义交集类型。这样,您可以将MyProps保留在自己的位置,让容器或组件在没有容器的地方使用,根据需要应用道具。我想这取决于你和你的用例 - 如果你定义的话 MyProps = MyStateProps & MyDispatchProps & MyOwnProps
,它与一个特定的容器绑在一起,这个容器灵活性较差(但不那么冗长)。
作为一个解决方案,它非常冗长,但我认为没有办法告诉TypeScript不同的所需道具将在不同的地方组装,并且 connect
将他们绑在一起。
此外,为了它的价值,我通常选择道具,为了简单起见,所以我没有太多的经验来分享使用这种方法。
12
2017-11-18 15:44
我只是用 Partial<MyProps>
,哪里 Partial
是一种内置的TypeScript类型,定义如下:
type Partial<T> = {
[P in keyof T]?: T[P];
}
它需要一个接口,并使其中的每个属性都是可选的。
这是我编写的表示/ Redux感知组件对的示例:
/components/ConnectionPane/ConnectionPane.tsx
export interface IConnectionPaneProps {
connecting: boolean;
connected: boolean;
onConnect: (hostname: string, port: number) => void;
}
interface IState {
hostname: string;
port?: number;
}
export default class ConnectionPane extends React.Component<IConnectionPaneProps, IState> {
...
}
/containers/ConnectionPane/ConnectionPane.ts
import {connect} from 'react-redux';
import {connectionSelectors as selectors} from '../../../state/ducks';
import {connect as connectToTestEcho} from '../../../state/ducks/connection';
import {ConnectionPane, IConnectionPaneProps} from '../../components';
function mapStateToProps (state): Partial<IConnectionPaneProps> {
return {
connecting: selectors.isConnecting(state),
connected: selectors.isConnected(state)
};
}
function mapDispatchToProps (dispatch): Partial<IConnectionPaneProps> {
return {
onConnect: (hostname, port) => dispatch(connectToTestEcho(hostname, port))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ConnectionPane) as any;
演示组件道具是非可选的 - 完全按照演示文稿的要求而不对相应的“智能”组件产生任何影响。
与此同时, mapStateToProps
和 mapDispatchToProps
将允许我在每个函数中分配所需的表示道具的子集,同时将在展示道具界面中未定义的任何道具标记为错误。
2
2018-06-27 17:14
interface MyStateProps {
name: string;
selected: boolean;
}
interface MyDispatchProps {
onSelect: (name: string) => void;
}
interface MyOwnProps {
section: string;
}
// Intersection Types
type MyProps = MyStateProps & MyDispatchProps & MyOwnProps;
class MyComponent extends React.Component<MyProps, {}> { }
function mapStateToProps(state: MyState): MyStateProps { }
function mapDispatchToProps(dispatch: IDispatch): MyDispatchProps { }
const MyContainer = connect<MyStateProps, MyDispatchProps, MyOwnProps>(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
你可以使用一些叫做的东西 交叉类型
https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types
1
2017-07-04 06:58