Dva: TypeScript 使用 connect 时的 OwnProps 接口问题

Created on 10 Jan 2018  ·  14Comments  ·  Source: dvajs/dva

Code to reproduce the issue: (请提供可复现的代码或者步骤)

interface IOwnProps {
  startDate: number
  endDate: number
}
interface IOwnState {
  current: number
}
const mapStateToProps = (state, ownProps: IOwnProps) => ({
  opEntitiesTable: getOpEntitiesTableData(state),
  ...ownProps,
})
const mapDispatchToProps = dispatch => ({
  fetchOpEntities: bindActionCreators(fetchOpEntities, dispatch),
})
const mapState = getReturnOfExpression(mapStateToProps)
const mapDispatch = getReturnOfExpression(mapDispatchToProps)
type IMapStateToProps = typeof mapState
type IMapDispatchToProps = typeof mapDispatch
type IProps = IMapStateToProps & IMapDispatchToProps

class LogTable extends React.Component<IProps, IOwnState> {
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(LogTable)

Expected behavior: (预期的正常效果)

使用该组件时, Props 类型应该按照 IOwnProps 来匹配而不是 IProps(包含了从 redux map 过来的)。因此,会提示 opEntitiesTable 需传。

Actual behavior: (实际效果)

应该按照 IOwnProps 来检查 props,所以使用该组件只需要传 startDateendDate 即可。

如果使用 react-redux 的 connect,该 connect 的 types 定义支持泛型,这样使用就正常了:

export default connect<IMapStateToProps, IMapDispatchToProps, IOwnProps>(
  mapStateToProps,
  mapDispatchToProps
)(LogTable)

使用该组件,会按照 IOwnProps 来检查 props。
dva 的 connect 的类型定义没有泛型支持。

Versions of packages used: (哪个库的哪个版本出现的问题)

1.2.1 版本

Most helpful comment

@ruiming 其实这个问题是 Ts 的,我自己项目没有使用dva也有这个问题,可以通过一个 hack 手段解决;
1、对于connect使用装饰器可以这么用 @(connect(mapStateToProps, mapDispatchToProps) as any)
2、对于提示 redux 注入属性需传递的问题,可以这么解决 export default LogTable as any;
可以参考我的项目代码1项目代码2

All 14 comments

我尝试修改 connect 的 type definition,可以看下这个:
https://github.com/dvajs/dva/compare/master...ruiming:patch-1

但是这样做会有新的问题,connect 无法使用装饰器语法 @connect,总是会提示不匹配,这个问题似乎还无解(https://github.com/DefinitelyTyped/DefinitelyTyped/issues/19020)。

但不适用装饰器语法的话,像下面这样写的,是可以正常工作的并正确检查 Props(只检查 IOwnProps):

export default connect<IMapStateToProps, IMapDispatchToProps, IOwnProps>(
  mapStateToProps,
  mapDispatchToProps
)(LogTable)

@ruiming 其实这个问题是 Ts 的,我自己项目没有使用dva也有这个问题,可以通过一个 hack 手段解决;
1、对于connect使用装饰器可以这么用 @(connect(mapStateToProps, mapDispatchToProps) as any)
2、对于提示 redux 注入属性需传递的问题,可以这么解决 export default LogTable as any;
可以参考我的项目代码1项目代码2

@yvanwangl 嗯,我之前用 Antd 的 @Form.create() 也是不能用,最后也是像你这样做解决的。

你说的第二点,这样做会丢失使用该组件时的 OwnProps 属性的静态检查吧?你可以参考我最上面"实际效果"的代码,通过 connect 的泛型支持是可以处理这个问题的。

@ruiming 嗯,我之前试过那么写,但是感觉如果很多组件都这么写有些许麻烦(懒)

@yvanwangl 但这样你这个组件对使用者而言,用没用 TypeScript 都一样了,没有了补全和静态检查。我不是很认可这种写法。不过确实麻烦了点,获取 mapStateToProps 的返回值类型还要通过污染运行时来实现。

@ruiming 是的 👍

@yvanwangl 但这样你这个组件对使用者而言,用没用 TypeScript 都一样了,没有了补全和静态检查。我不是很认可这种写法。不过确实麻烦了点,获取 mapStateToProps 的返回值类型还要通过污染运行时来实现。

是不是用 dva 和 ts 后。所有组件的 Props 都需要设置为any?请问这个问题解决了吗。

同求类似 redux 的泛型支持,现在 stateProps 和 dispatchProps 都会污染真实组件参数,很影响封装组件的体验

@ouabing 可以先试着直接用 Redux 的 connect 而不是 dva 的。另外 TS 已经有了 returnType 运算符了,我前面的 demo 太啰嗦了。

@ruiming 我试试

所以dva的connect会支持泛型吗?或者我直接用react-redux的connect?

import { ComponentClass } from 'react'
import {
  connect as nativeConnect,
  MapDispatchToPropsParam,
  MapStateToPropsParam
} from 'react-redux'

export type ComponentDecorator<P = any> = <T extends ComponentClass<P>>(WrappedComponent: T) => T

export const connect: <P, S>(
  mapState: MapStateToPropsParam<Partial<P>, P, S>,
  mapDispatch?: MapDispatchToPropsParam<Partial<P>, P>
) => ComponentDecorator = nativeConnect as any

The same question.

是否有最优解

Was this page helpful?
0 / 5 - 0 ratings