reactjs 将forwardRef与useImperativeHandle一起使用时,ForwardRefExoticComponent不可分配给类型CumentType

h7wcgrx3  于 2023-10-17  发布在  React
关注(0)|答案(1)|浏览(160)

我们正在使用typescript开发一个内部react库,它有一个组件,这里称为Parent,我们希望能够接收一个自定义组件作为要渲染的 prop ,但也可以从Parent调用子组件函数。为此,我们使用forwardRef和useImperativeHandle。为了确保所有作为props传入的组件都具有正确的功能,我们有一个名为CustomFormProps的接口,如下所示:

export interface CustomFormProps<T> {
  getValue: () => T | null;
  reset: () => void;
}

Parent组件的属性类型为ParentProps。

export interface ParentProps<T> {
  CustomFilterFormComponent?: React.ComponentType<
    CustomFormProps<T> & React.RefAttributes<T>
  >;
}

Parent相对简单,呈现一个div、自定义组件和一个触发自定义组件中函数的按钮。

const Parent = <T extends object>({
  CustomFilterFormComponent
}: ParentProps<T>) => {
  const customFormRef = useRef<any>(null);

  const customFormProps: any = {
    ref: customFormRef
  };

  const handleReset = () => {
    if (customFormRef.current) {
      customFormRef.current.reset();
    }
  };

  return (
    <div>
      <div>Hello</div>
      {CustomFilterFormComponent && (
        <CustomFilterFormComponent {...customFormProps} />
      )}
      <button onClick={handleReset}>Reset</button>
    </div>
  );
};

我有一个传递给Parent的示例组件。代码工作正常,但是在我们将CustomFilterFormComponent传递给Parent的那一行,我们得到了这个错误:
类型“ForwardRefExoticComponent<CustomFilterFormFilters & RefAttributes>"不能分配给类型”ForwardRefExoticType <CustomFormProps & RefAttributes>“|未定义'。类型“ForwardRefExoticComponent<CustomFilterFormFilters & RefAttributes>"不能分配给类型”FunctionComponent<CustomFormProps & RefAttributes“。参数”props“和”props“的类型不兼容。类型“CustomFormProps & RefAttributes "不可分配给类型”CustomFilterFormFilters & RefAttributes“。类型”CustomFormProps & RefAttributes“中缺少属性”upcs“,但类型”CustomFilterFormFilters“中需要该属性。
这里是一个链接到一个codesandbox,我能够重现错误:https://codesandbox.io/s/loving-kapitsa-ysn9g7?file=/src/App.tsx
这里是完整的源代码:

import { useImperativeHandle, useRef, useState } from "react";
import "./styles.css";
import React from "react";

export interface CustomFormProps<T> {
  getValue: () => T | null;
  reset: () => void;
}

export interface ParentProps<T> {
  CustomFilterFormComponent?: React.ComponentType<
    CustomFormProps<T> & React.RefAttributes<T>
  >;
}

interface CustomFilterFormFilters {
  upcs: number[];
}

const YourCustomFilterFormComponent = React.forwardRef<
  CustomFormProps<CustomFilterFormFilters>,
  CustomFilterFormFilters
>(
  (
    props: CustomFilterFormFilters,
    ref: React.Ref<CustomFormProps<CustomFilterFormFilters>>
  ) => {
    const [upcs, setUpcs] = useState<any[]>(props.upcs ?? []);

    const upcOptions = [12345, 56789, 98635];

    const getValue = (): CustomFilterFormFilters | null => {
      if (upcs.length > 0) {
        return { upcs } as CustomFilterFormFilters;
      }

      return null;
    };

    useImperativeHandle(ref, () => ({
      getValue,
      reset: () => {
        setUpcs([]);
      }
    }));

    const handleSelection = (upc: number, selected: boolean) => {
      if (selected) {
        if (upcs.indexOf(upc) === -1) setUpcs([...upcs, upc]);
      } else {
        setUpcs(upcs.filter((q) => q != upc));
      }
    };

    return (
      <div>
        {upcOptions.map((upc, idx) => (
          <div key={idx}>
            <input
              type="checkbox"
              id={`chkCustomFilterForm-${idx}`}
              checked={upcs.indexOf(upc) > -1}
              onChange={(evt) => {
                handleSelection(upc, evt.target.checked);
              }}
            />
            <label htmlFor={`chkCustomFilterForm-${idx}`}>{upc}</label>
          </div>
        ))}
      </div>
    );
  }
);

const Parent = <T extends object>({
  CustomFilterFormComponent
}: ParentProps<T>) => {
  const customFormRef = useRef<any>(null);

  const customFormProps: any = {
    ref: customFormRef
  };

  const handleReset = () => {
    if (customFormRef.current) {
      customFormRef.current.reset();
    }
  };

  return (
    <div>
      <div>Hello</div>
      {CustomFilterFormComponent && (
        <CustomFilterFormComponent {...customFormProps} />
      )}
      <button onClick={handleReset}>Reset</button>
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <Parent CustomFilterFormComponent={YourCustomFilterFormComponent} />
    </div>
  );
}

任何帮助都非常感谢。谢谢你,谢谢!

jyztefdp

jyztefdp1#

看起来ParentPropsReact.ComponentType的期望值和React.forwardRefYourCustomFilterFormComponent的定义不匹配。
如何修改ParentProps

export interface ParentProps<T> {
  CustomFilterFormComponent?: React.ForwardRefExoticComponent<T>;
}

警告消失后,似乎仍按预期工作。https://codesandbox.io/s/amazing-matan-p8cwwc
ParentProps的这个新定义可以在您提供的可复制示例中工作,但是如果您的代码库的其他部分不适用,请更新您的问题,说明此类型定义需要涵盖的范围。

相关问题