多个道具类型,“任意”类型不能分配为“从不”类型

时间:2019-11-13 06:50:06

标签: reactjs typescript

对不起,我不知道确切的名字。

使用react和typescript: 我有一个组件,它根据我作为道具传递的类型来创建一个组件集:

interface FieldDispatcherProps {
  children: Array<never>;
  fieldId: string;
  mandatory?: boolean;
  mode: FieldMode;
  onChange: Function;
}

const fieldTypes = {
  [FieldsHelper.fields.text.value] : TextField,
  [FieldsHelper.fields.textarea.value] : TextAreaField,
  [FieldsHelper.fields.select.value] : SelectField,
  [FieldsHelper.fields.radio.value] : RadioField,
  [FieldsHelper.fields.checkbox.value] : CheckboxField,
  [FieldsHelper.fields.autonum.value] : AutonumField,
  [FieldsHelper.fields.number.value] : NumberField,
  [FieldsHelper.fields.file.value] : FileField,
  [FieldsHelper.fields.calc.value] : CalcField,
  [FieldsHelper.fields.user.value] : UserField,
  [FieldsHelper.fields.dslookup.value] : LookupField,
  [FieldsHelper.fields.date.value] : DateField,
  [FieldsHelper.fields.time.value] : TimeField,
}

const FieldDispatcher = (props: FieldDispatcherProps): JSX.Element => {
  const {fieldId, mandatory, mode, onChange}: FieldDispatcherProps = props;
  const field = useSelector((state: RootState) => ItemDetailsSelectors.getFieldById(state))(fieldId);
  const value = useSelector((state: RootState) => ItemDetailsSelectors.getEntryValue(state))(fieldId);
  return (
    <div>
      {((): JSX.Element  => {
        const FieldType = fieldTypes[field.dataType];
        if(FieldType) {
          return <FieldType onChange={onChange} mode={mode} mandatory={mandatory} field={field} value={value} fieldId={fieldId}/>
        } else {
          return <div>{value}</div>;
        }
      })()}
    </div>
  )
}

现在,每个字段都具有相同的道具名称,但是名为value的道具在每个组件中具有不同的类型。有些人期望一个数组,另外一个字符串,另外一个数字。...

我面临的问题是

        const FieldType = fieldTypes[field.dataType];
        if(FieldType) {
          return <FieldType onChange={onChange} mode={mode} mandatory={mandatory} field={field} value={value} fieldId={fieldId}/>
        } else {
          return <div>{value}</div>;
        }

返回以下错误以获取props值:

  

类型“ any”不能分配给类型“ never”。

如果我让所有孩子都期望它可以使用任何类型的值,但我想保留孩子类型。

有办法吗?

2 个答案:

答案 0 :(得分:1)

我不确定如何在此处给出具体答案,因为您在示例代码中使用了一堆未知的帮助程序和类型。一般来说,我想到了两种选择来处理value的键入:

1。)将基本类型注释为fieldTypes,该基本类型将value声明为any

type BaseProps<T> = {
  value: T;
};

const TextField = (p: BaseProps<string>) => <span>{p.value}</span>;
const RadioField = (p: BaseProps<boolean>) => <span>{p.value}</span>;

const fieldTypes: { [K: string]: (props: BaseProps<any>) => JSX.Element } = {
  a: TextField,
  b: RadioField
};

因此,您无需更改子组件类型即可期望value类型的any,只需更改fieldTypes映射类型。没关系,您通过value检索的useSelector(..)将适合any

2。)通过类型保护/控制流缩小精确的value类型:

const FieldDispatcher = (props: FieldDispatcherProps) => {
  const value = useSelector( .. ) // value comes from somewhere
  // field.dataType comes from somewhere 
  // lets assume, fieldTypes looks like {"a" : TextField , "b" : CheckboxField}
  const dataType: keyof typeof fieldTypes = ...  

  let fieldTypeJsx: JSX.Element;
  switch (dataType) {
    case "a": {
      // dataType narrowed to "a" here, so fieldTypes[dataType]
      // contains the specific Field Comp
      const FieldType = fieldTypes[dataType];
      // depends on value type, if you have to type cast here
      fieldTypeJsx = <FieldType value={value as string} />;
      break;
    }
    case "b": {
      // analogue to case "a"
      const FieldType = fieldTypes[dataType];
      fieldTypeJsx = <FieldType value={value as boolean} />;
      break;
    }
    default: {
      return <div>{value}</div>;
    }
  }

答案 1 :(得分:0)

这里的问题是,您将children的类型声明为Array<never>,因此,在传递子代时,由于至少有一个子代不是never类型,因此子级数组是anyaccording to the docs类型的数组:

  

[...] no 类型是never的子类型或可分配给never本身的子类型。甚至any也无法分配给never

因此,将children更改为Array<any>类型(或更具体的类型)将解决此问题。

但是,您提到您想保留孩子的类型。类型never的数组似乎是children数组的奇怪类型,而另一个类型(如Array<any>)似乎更合适。另外,如果您确实需要将孩子保留为Array<never>,则也许该道具不应该是children,而应该是另一个道具。