te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - Inferring mapped props when using TypeScript and React-Redux - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Inferring mapped props when using TypeScript and React-Redux - Stack Overflow

programmeradmin4浏览0评论

I found a way to get type safety when using mapStateToProps from react-redux: as documented you can define an interface and parameterize React.Component<T> with your interface.

However, when I am defining mapStateToProps, I'm already defining a function where the types of the properties of the resulting object can be inferred. Eg,

function mapStateToProps(state: MyState) {
    return {
        counter: state.counter
    };
}

Here, the prop counter can be inferred to be the same type as state.counter. But I still have to have boilerplate code like the following:

interface AppProps {
    counter: number;
}


class App extends React.Component<AppProps> { ... }

export default connect(mapStateToProps)(App);

So the question is, is there any way to structure the code so that I can avoid writing the type of counter twice? Or to avoid parameterizing the type of React.Component -- even if I could have the props of the ponent inferred from an explicitly-hinted result type of the mapStateToProps function, that would be preferable. I am wondering if the duplication above is indeed the normal way to write typed ponents using React-Redux.

I found a way to get type safety when using mapStateToProps from react-redux: as documented you can define an interface and parameterize React.Component<T> with your interface.

However, when I am defining mapStateToProps, I'm already defining a function where the types of the properties of the resulting object can be inferred. Eg,

function mapStateToProps(state: MyState) {
    return {
        counter: state.counter
    };
}

Here, the prop counter can be inferred to be the same type as state.counter. But I still have to have boilerplate code like the following:

interface AppProps {
    counter: number;
}


class App extends React.Component<AppProps> { ... }

export default connect(mapStateToProps)(App);

So the question is, is there any way to structure the code so that I can avoid writing the type of counter twice? Or to avoid parameterizing the type of React.Component -- even if I could have the props of the ponent inferred from an explicitly-hinted result type of the mapStateToProps function, that would be preferable. I am wondering if the duplication above is indeed the normal way to write typed ponents using React-Redux.

Share Improve this question asked Oct 30, 2019 at 10:30 amoeamoe 4,5695 gold badges33 silver badges52 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 11

Yes. There's a neat technique for inferring the type of the bined props that connect will pass to your ponent based on mapState and mapDispatch.

There is a new ConnectedProps<T> type that is available in @types/[email protected]. You can use it like this:

function mapStateToProps(state: MyState) {
    return {
        counter: state.counter
    };
}

const mapDispatch = {increment};

// Do the first half of the `connect()` call separately, 
// before declaring the ponent
const connector = connect(mapState, mapDispatch);

// Extract "the type of the props passed down by connect"
type PropsFromRedux = ConnectedProps<typeof connector>
// should be: {counter: number, increment: () => {type: "INCREMENT"}}, etc

// define bined props
type MyComponentProps = PropsFromRedux & PropsFromParent;

// Declare the ponent with the right props type
class MyComponent extends React.Component<MyComponentProps> {}

// Finish the connect call
export default connector(MyComponent)

Note that this correctly infers the type of thunk action creators included in mapDispatch if it's an object, whereas typeof mapDispatch does not.

We will add this to the official React-Redux docs as a remended approach soon.

More details:

  • Gist: ConnectedProps - the missing TS helper for Redux
  • Practical TypeScript with React+Redux
  • DefinitelyTyped #31227: Connected ponent inference
  • DefinitelyTyped PR #37300: Add ConnectedProps type

I don't think so. You could make your setup more concise by using Redux hooks: https://react-redux.js/next/api/hooks

    // Your function ponent . You don't need to connect it
    const App: React.FC = () => {
      const counter = useSelector<number>((state: MyState) => state.counter);
      const dispatch = useDispatch(); // for dispatching actions
    };

Edit: You can if you just use the same MyState type. But I don't think you would want that.

I would type mapped dispatch props, and ponent props separately and then bine the inferred type of the mapped state to props function. See below for a quick example. There might be a more elegant solution but hopefully, it will hopefully get you on the right track.

import * as React from "react";
import { Action } from "redux";
import { connect } from "react-redux";

// Lives in some lib file
type AppState = {
  counter: number;
};

type MappedState = {
  putedValue: number;
};
type MappedDispatch = {
  doSomethingCool: () => Action;
};
type ComponentProps = {
  someProp: string;
};

const mapStateToProps = (state: AppState) => ({
  putedValue: state.counter
});

const mapDispatchToProps: MappedDispatch = {
  doSomethingCool: () => {
    return {
      type: "DO_SOMETHING_COOL"
    };
  }
};

type Props = ReturnType<typeof mapStateToProps> &
  MappedDispatch &
  ComponentProps;

class DumbComponent extends React.Component<Props> {
  render() {
    return (
      <div>
        <h1>{this.props.someProp}</h1>
        <div>{this.props.putedValue}</div>
        <button onClick={() => this.props.doSomethingCool()}>Click me</button>
      </div>
    );
  }
}

const SmartComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(DumbComponent);

export default SmartComponent;
发布评论

评论列表(0)

  1. 暂无评论