【问题标题】:What is the proper way to type lodash functions?输入 lodash 函数的正确方法是什么?
【发布时间】:2019-05-07 22:08:07
【问题描述】:

我很难为使用 lodash 方法通过选择器连接到 redux 存储的 React 组件编写正确的类型。

this article's conventions 之后,我的组件的简化版本如下所示

reducers/index.ts

interface ApiState {
  api: {
    entities: {
      subscriptions: {
        [pk: number]: {
          imageUrl: string;
          pk: number;
          slug: string;
          title: string;
        };
      };
    };
    result: {
      subscriptions: never[];
    };
  };
  …
};

export type RootState =
  | (ApiState &
      FirebaseState & {
        router: Reducer<RouterState, LocationChangeAction>;
      })
  | {};

src/components/MyComponent.tsx

import React, {PureComponent} from "react";
import {connect} from "react-redux";
import {RootState} from "~/reducers";

interface OwnProps {
  label: "host" | "experience";
  score: number;
  subscriptionPk: number;
}
interface StateProps {
  subscription?: {
    pk: number;
    title: string;
  };
}

const selectSubscriptions = state => state.api.entities.subscriptions;


const mapStateToProps = (state: RootState, ownProps: OwnProps): StateProps => ({
  subscription: _.find(selectSubscriptions(state), {
    pk: ownProps.subscriptionPk,
  }) as any,
});

type Props = StateProps & OwnProps;

export default connect<StateProps, {}, OwnProps>(mapStateToProps)(
  class extends PureComponent<Props> {
    render() {
      const {label, score, subscription} = this.props;

      return (
        <div>
          {label} {score} {subscription.title}
        </div>
      );
    }
  },
);

src/typings.d.ts

// lodash global typing - begin
declare namespace _ {} // eslint-disable-line no-unused-vars
// lodash global typing - end

上面的代码在 lodash find 方法被转换为 any 之前工作:subscription: _.find() as any, in mapStateToProp。

如果我删除 as any,我会收到以下错误:

$ tsc --project tsconfig.json
src/components/MyComponent.tsx:37:3 - error TS2322: Type '{ pk: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; [Symbol.iterator]: ...; }; } | undefined' is not assignable to type '{ pk: number; slug: string; title: string; } | undefined'.
  Type '{ pk: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; [Symbol.iterator]: ...; }; }' is missing the following properties from type '{ pk: number; slug: string; title: string; }': slug, title

37   subscription: _.find(selectSubscriptions(state), {
     ~~~~~~~~~~~~

  src/components/MyComponent.tsx:26:3
    26   subscription?: {
         ~~~~~~~~~~~~
    The expected type comes from property 'subscription' which is declared here on type 'StateProps'


Found 1 error.

为什么 lodash 不能正确识别类型?我宁愿不必将所有 lodash 调用都转换为 any...

使用的版本:

  • 反应 16.6.3
  • redux 4.0.1
  • react-redux 5.1.1
  • lodash-webpack-plugin 0.11.5(本身使用 lodash ^4.17.4)
  • @types/lodash 4.14.119

【问题讨论】:

    标签: typescript redux react-redux lodash typescript-typings


    【解决方案1】:

    只是不要提供泛型类型来不必要地连接。

    在这里

    import _ from "lodash";
    import { PureComponent } from "react";
    import React from "react";
    import { connect } from "react-redux";
    
    interface IApiState {
      api: {
        entities: {
          subscriptions: {
            [pk: number]: {
              imageUrl: string;
              pk: number;
              slug: string;
              title: string;
            };
          };
        };
        result: {
          subscriptions: never[];
        };
      };
    }
    
    export type RootState = IApiState;
    
    interface IOwnProps {
      label: "host" | "experience";
      score: number;
      subscriptionPk: number;
    }
    interface ISubscription {
      pk: number;
      title: string;
    }
    interface IStateProps {
      subscription?: ISubscription;
    }
    
    const selectSubscriptions = (state: RootState) =>
      state.api.entities.subscriptions;
    
    const mapStateToProps = (
      state: RootState,
      ownProps: IOwnProps,
    ) => ({
      subscription: _.find(selectSubscriptions(state), {
        pk: ownProps.subscriptionPk,
      }),
    });
    
    type Props = IStateProps & IOwnProps;
    
    export default connect(mapStateToProps)(
      class extends PureComponent<Props> {
        public render() {
          const { label, score, subscription } = this.props;
    
          return (
            <div>
              {label} {score} {subscription && subscription.title}
            </div>
          );
        }
      },
    );
    

    【讨论】:

    • 感谢您的回复!我尝试更改_.find() as any_.find()connect&lt;StateProps, {}, OwnProps&gt;connect,但_find 行上的错误仍然存​​在。这似乎不是解决方案。此外,我发现 connect 泛型类型声明对于理解它通常期望的内容非常有用。
    • 您的示例还提示了一个不相关的问题。老实说,我还不清楚类型和接口之间的区别,在我目前的使用情况下,它看起来几乎是一样的(接口更灵活一些)。因此,我想知道为什么有几个人使用这个 I 前缀命名约定来区分接口和类型。只是偏好/习惯的问题,还是背后有更严重的原因?
    • 我在我的一个解决方案上尝试了这个,并且我使用了一个要求 I 在接口名称之前的 linter,这只是一个约定。但是,就像我说的那样,我试过了,它奏效了。那么如果有可能你可以创建一个 git repo 吗?
    猜你喜欢
    • 2019-10-16
    • 2019-02-22
    • 2016-06-07
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多