【问题标题】:Typescript/React ForwardRefExoticComponent assignment with more specific HTMLElement ref failsTypescript/React ForwardRefExoticComponent 分配更具体的 HTMLElement ref 失败
【发布时间】:2021-04-06 08:34:29
【问题描述】:

我正在尝试编写一个 HOC 并键入您可以传递给它的孩子。

场景看起来有点像这样(也在这个沙箱中:https://codesandbox.io/s/amazing-taussig-h2dpm?file=/src/App.tsx):

interface HOCProps {
    modules: React.ForwardRefExoticComponent<
        HOCChildProps & React.RefAttributes<HTMLElement>
    >[];
}
interface HOCChildProps {
    ...
}
declare const HOC: React.FC<HOCProps>;

// this produces an error in HOCTest if HTMLDivElement is used
// and an error in HOCChildTest if HTMLElement is used
// as the ref type in React.forwardRef
const HOCChildTest = React.forwardRef<HTMLDivElement, HOCChildProps>(
    (props, ref) => (
        <div ref={ref}>
            ...
        </div>
    )
);
const HOCTest: React.FC = () => <HOC modules={[HOCChildTest]} />;

代码仍在工作,但打字没有。

看来这个分配失败了:

declare const divTest: React.ForwardRefExoticComponent<
    React.RefAttributes<HTMLDivElement>
>;

export const htmlTest: React.ForwardRefExoticComponent<
    React.RefAttributes<HTMLElement>
> = divTest;

Typescript 错误信息:

Type 'ForwardRefExoticComponent<RefAttributes<HTMLDivElement>>' is not assignable to type 'ForwardRefExoticComponent<RefAttributes<HTMLElement>>'.
  Types of parameters 'props' and 'props' are incompatible.
    Type 'RefAttributes<HTMLElement>' is not assignable to type 'RefAttributes<HTMLDivElement>'.

在最后一行中,它指出我正在尝试将 RefAttributes&lt;HTMLElement&gt; 分配给 RefAttributes&lt;HTMLDivElement&gt;,但我以相反的方式进行分配(如第一行正确显示的那样)。

我错过了什么吗?因为我假设具有更具体 HTMLDivElement ref 的组件可以分配给具有更通用 HTMLElement ref 的组件。

【问题讨论】:

    标签: reactjs typescript react-ref


    【解决方案1】:

    forwardRef 可以转发的ref 类型之一是回调引用。如果您处理过传递回调,那么您会知道extends 在处理回调时有点“倒退”。但是forwardRef也可以转发RefObject

    由于您正在处理对象和回调的联合,因此您需要 exact 正确的 ref 类型。它不能更宽或更窄。

    这里有一些例子来澄清它:

    // ok
    const f = (ref: (instance: HTMLDivElement | null) => void) => <div ref={ref}/>
    
    // ok
    const f = (ref: MutableRefObject<HTMLDivElement | null>) => <div ref={ref}/>
    
    // ok because HTMLDivElement extends HTMLElement
    const f = (ref: (instance: HTMLElement | null) => void) => <div ref={ref}/>
    
    // error because HTMLElement is not assignable to HTMLDivElement
    const f = (ref: MutableRefObject<HTMLElement | null>) => <div ref={ref}/>
    
    // error because a div ref can only be assigned to a div
    const f = (Element: "div" | "a", ref: MutableRefObject<HTMLDivElement | null>) => <Element ref={ref}/>
    
    // error because we need a more exact ref type
    const f = (Element: "div" | "a", ref: MutableRefObject<HTMLElement | null>) => <Element ref={ref}/>
    
    // ok - the only possible ref here must be both a div and an a
    const f = (Element: "div" | "a", ref: MutableRefObject<(HTMLDivElement & HTMLAnchorElement) | null>) => <Element ref={ref}/>
    

    我原以为这是一个错误,但显然不是。

    const f = (Element: "div" | "a", ref: (instance: (HTMLDivElement & HTMLAnchorElement) | null) => void) => <Element ref={ref}/>
    

    所以现在我偶然发现了一个可能的解决方案,即您的 ref 可以是所有单个 ref 类型的交集。

    如果不知道HOC 的作用,很难说最好的解决方案是什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-09-29
      • 2019-07-14
      • 2020-02-01
      • 1970-01-01
      • 2021-09-22
      • 1970-01-01
      • 2019-08-15
      • 2019-07-18
      相关资源
      最近更新 更多