是否可以在不丢失对象验证的情况下为有条件要求的对象数组编写自定义道具类型验证器?

Is it possible to write custom prop-type validator for conditionally required array of objects without losing object validation?

我在 React 组件中使用 prop-types。该组件有一个属性 data,它应该是一个对象数组,如下所示:[{value: 'some string', id: 123}]。我想添加一个自定义道具类型函数,如果 props.useCustomSuggestionsfalse,则需要 data。我试过这样的事情:

data: (props) => {
  if (!props.useCustomSuggestions && !props.data) {
    return new Error('Data must be provided to use default suggestions');
  } else if (props.data && typeof props.data !== 'object') {
    return new Error(
      'Data must be an array',
    );
  }
};

我相信这可以验证当 props.useCustomSuggestionsfalse 时是否需要数组,但它不会检查 data 中的对象格式是否正确。是否有另一种方法可以验证数组由具有字符串类型 value 和数字类型 id 的属性的对象组成?

我认为 React 中的 customArrayProp 文档可能是解决方案,但它没有传递整个 props 对象,所以我失去了根据 [ 的值有条件地要求 data 的能力=22=].

这似乎可以解决问题,如果有人有更简洁的答案,或者对下面的代码有反馈,请继续评论或post您自己的答案。

data: (props) => {
  if (!props.useCustomSuggestions && !props.data) {
    return new Error('Data must be provided to use default suggestions');
  } else if (props.data && !Array.isArray(props.suggestions)) {
    return new Error('Data must be an array');
  } else if (props.data.length > 0) {
    for (let i = 0; i < props.data.length; i += 1) {
      if (!props.data[i].value || !props.data[i].id) {
        return new Error(
          'Objects in data must include properties "value" and "id"',
        );
      } else if (
        typeof props.data[i].value !== 'string' ||
        typeof props.data[i].id !== 'number'
      ) {
        return new Error(
          'Objects in data array must have property "value" of type string, and "id" of type number',
        );
      }
    }
  }
},

call propTypes check directly 有一种特殊的方法可以重用他们的检查逻辑:PropTypes.checkPropTypes()

data: (props, propName, componentName) => {
  if (props.useCustomSuggestion) {  // data should be validated but is optional
    PropTypes.checkPropTypes({ 
        [propName]: PropTypes.arrayOf(
          PropTypes.shape({
            value: PropTypes.string.isRequired,
            id: PropTypes.number.isRequired
         }) 
        ) 
      }, 
      props, 
      propName, 
      componentName
    );
  } else { // data is required
    PropTypes.checkPropTypes({ 
        [propName]: PropTypes.arrayOf(
          PropTypes.shape({
            value: PropTypes.string.isRequired,
            id: PropTypes.number.isRequired
         }) 
        ).isRequired
      }, 
      props, 
      propName, 
      componentName
    );
  }
}

PS 出于未知原因,codesandbox 有时会 运行 propTypes 检查,有时会默默地跳过它,所以我的代码示例不是 100% 有效。但是我已经检查了 string/number 的方法——就在我试图将其应用于 arrayOf/shape 时,它开始变得奇怪了。

也许您可以将公共部分(shape 的内部)移动到中间变量以减少代码重复,但正如我所说无法确保。