【问题标题】:Is there a way in React to change a prop type to avoid TypeErrors?React 中是否有办法更改道具类型以避免 TypeErrors?
【发布时间】:2021-02-19 19:05:10
【问题描述】:

我想知道如果传递的道具类型不是预期的类型,是否有办法更改道具类型。

例如,如果我的组件希望接收一个对象(使用 PropTypes 或使用 TypeScript 表示法),但传递了一个数组,则该数组应转换为一个对象(它可以是一个空对象)。

有办法存档吗?

例子:

const array = [1, 2, 3];

<Component name={array} />

然后在我的组件内部:

const Component({ name }) {

    console.log(typeof name);
    // output: 'string'  

    console.log(name);
    // output: ''

    return (
        <div />
    );
}

Component.propTypes = {
   name: PropTypes.string
}

【问题讨论】:

  • 你能用一些代码解释你的问题吗?
  • @AjeetShah 这个例子有帮助吗?
  • 下面的答案应该对您有所帮助。不是吗?

标签: javascript reactjs typescript properties


【解决方案1】:

您可能想使用generic type。记录为:

软件工程的一个主要部分是构建组件,这些组件不仅具有定义明确且一致的 API,而且还可以重用。能够处理当今数据和未来数据的组件将为您提供构建大型软件系统的最灵活能力。

在 C# 和 Java 等语言中,工具箱中用于创建可重用组件的主要工具之一是泛型,也就是说,能够创建一个可以在多种类型而不是单一类型上工作的组件。这允许用户使用这些组件并使用他们自己的类型。

然后您可以转换为所需的类型:

const convert2Array = <T>(prop: T): T[] => {
    let arr: T[];
    if (Array.isArray(prop)) {
        arr = prop;
    } else if (typeof prop === 'object' && prop !== null) {
        arr = Object.values(prop);
    } else {
        arr = [prop];
    } 

    return arr;
};

convert2Array('str'); // ['str']
convert2Array(7); // [7]
convert2Array(['an', 'existing', 'array']); // ['an', 'existing', 'array']
convert2Array({foo: 'bar', zip: 'zap'}); // ['bar', 'zap']

【讨论】:

    【解决方案2】:

    arrayobject 的子类型,因此在打字稿中将array 作为object 传递已经很好了。

    关于其他道具转换:您可以使用高阶组件来完成此操作,该组件采用“扩展”道具并将它们映射到它们的预期类型。打字稿类型并不太难。这变得棘手的部分是这样编写它,以便 javascript 代码知道要转换哪些道具,因为 typescript 类型在运行时被删除。

    我提出的解决方案要求您指定要转换的道具的键。这不是我写过的最优雅的东西,但它确实有效!

    const withExpandedProps = <Keys extends string, Converter extends (value: any) => any>(
      keys: Keys[],
      convert: Converter
    ) => <Props extends {}>(Component: React.ComponentType<Props>) => (
      props: Omit<Props, Keys> & Record<Keys, Expanded<Converter>>
    ) => {
      const newProps = Object.fromEntries(
        Object.entries(props).map(([key, value]) => {
          const mappedVal = (keys as string[]).includes(key)
            ? convert(value as any)
            : value;
          return [key, mappedVal];
        })
      ) as Props;
    
      return <Component {...newProps} />;
    };
    

    用作:

    interface MyComponentProps {
      num: number;
      str: string;
      obj: object;
    }
    
    const MyComponent: React.FC<MyComponentProps> = ({ num, str, obj }) => {
      console.log({ num, str, obj });
      return (
        <div>
          <div>#{num}</div>
          <div>{str}</div>
          <ul>
            {Object.keys(obj).map((key) => (
              <li key={key}>{key}</li>
            ))}
          </ul>
        </div>
      );
    };
    
    const NewComponent = withExpandedProps(
      // all variables in javascript have a toString property
      ["str"],
      (value: any) => value.toString()
    )(
      withExpandedProps(
        // convert strings to numbers -- might return NaN which is type number
        ["num"],
        (value: string | number) =>
          typeof value === "string" ? parseFloat(value) : value
      )(MyComponent)
    );
    
    const Test = () => (
      <NewComponent
        num={"5"} // string | number
        str={["one", "two"]} // any
        obj={["one", "two"]} // object
      />
    );
    

    (稍后将编辑更多解释)

    【讨论】:

      猜你喜欢
      • 2023-02-20
      • 1970-01-01
      • 1970-01-01
      • 2019-12-20
      • 1970-01-01
      • 2020-06-23
      • 2019-11-07
      • 2014-05-24
      • 2017-07-15
      相关资源
      最近更新 更多