Definitelytyped: [@types/react] useRef 返回类型与 ref prop 类型冲突

创建于 2019-05-19  ·  12评论  ·  资料来源: DefinitelyTyped/DefinitelyTyped

Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'string | ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined'.
  Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'RefObject<HTMLDivElement>'.
    Types of property 'current' are incompatible.
      Type 'HTMLDivElement | undefined' is not assignable to type 'HTMLDivElement | null'.
        Type 'undefined' is not assignable to type 'HTMLDivElement | null'.

最有用的评论

一个稍微整洁的解决方案是在 useRef 函数调用中将 initialValue 设置为 null

const componentRef = useRef<HTMLDivElement>(null);

这确保了 componentRef = HTMLDivElement | null是 ref 属性所期望的,而不是HTMLDivElement | undefined

所有12条评论

编辑2:忽略我的解决方案,使用下面的一个:)

我目前有同样的问题,您是否已经找到了解决方案?

编辑:我现在正在使用这个,诚然不是那么漂亮,解决方案:

const inputField = React.useRef() as React.MutableRefObject<HTMLInputElement>;

在这里找到: https ://github.com/DefinitelyTyped/DefinitelyTyped/issues/28884#issuecomment -471341041

一个稍微整洁的解决方案是在 useRef 函数调用中将 initialValue 设置为 null

const componentRef = useRef<HTMLDivElement>(null);

这确保了 componentRef = HTMLDivElement | null是 ref 属性所期望的,而不是HTMLDivElement | undefined

@shane935先生,你让我很开心🙌🏻

在我看来undefined应该添加到RefObject<T>.current中,例如:

//index.ts, line 80
interface RefObject<T> {
   readonly current: T | null;
}

所以它读

//index.ts, line 80
interface RefObject<T> {
   readonly current: T | null | undefined;
}

这不是一个错误,它捕获了一个合法的打字错误。

有关更多详细信息,请参阅https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38228#issuecomment -529749802

正如@Jessidhia所说,这不是一个错误,也许你应该这样写。

import React, {
  forwardRef,
  ForwardRefRenderFunction,
  useImperativeHandle,
  useRef,
  PropsWithChildren,
} from "react";

interface Props {}
interface Ref {
  value: string;
  setValue: (value: string) => void;
}

const InputEmail: ForwardRefRenderFunction<Ref, PropsWithChildren<Props>> = (
  props,
  ref
) => {
  // hooks
  const inputElement = useRef<HTMLInputElement | null>(null);
  useImperativeHandle(ref, () => {
    return {
      value: inputElement.current ? inputElement.current.value : "",
      setValue: (value: string) => {
        inputElement.current && (inputElement.current.value = value);
      },
    };
  });

  // render
  return (
    <div>
      <input
        type="text"
        ref={inputElement}
        defaultValue="[email protected]"
        disabled
      />
    </div>
  );
};

const Component = forwardRef(InputEmail);

export default Component;

我不确定这是否能解决每个人的问题,而且我不是这方面的专家,但是在查看了我作为 ref 传入的内容的类型以及我将 ref 传递到的组件的实际 ref 类型之后,好像我的接口错了。

对于接收组件,我最初有一个道具接口,如下所示:

type TextboxProps = CustomProps & React.HTMLProps<HTMLInputElement>

我改为:

type TextboxProps = CustomProps & React.HTMLAttributes<HTMLInputElement>

打字错误然后消失了。

我不会假装我比我知道的更多,但是查看 HTMLProps 接口和 React.forwardRef() 函数类型的类型,你可以看到它正在使用 RefAttributes. 就在上面,您可以看到 ClassAttributes输入 HTMLProps正在扩展,其中定义了 LegacyRef我认为导致我的打字问题的类型。

看起来这个项目有 3 个useRef()重载,我们需要全部 3 个吗? 似乎useRef<T>(null)案例是开发人员最常使用的案例。

    function useRef<T>(initialValue: T): MutableRefObject<T>;
    function useRef<T>(initialValue: T|null): RefObject<T>;
    function useRef<T = undefined>(): MutableRefObject<T | undefined>;
  1. 这两个可变重载的预期用例是什么?
  2. 是否有其他方法可以支持用户可以更轻松地找到“正确”的重载?

我有RefObject

Screen Shot 2020-08-23 at 1 06 16 PM

我将它作为道具ref传递给我的Panel组件:

Screen Shot 2020-08-23 at 1 06 04 PM

我尝试使用forwardRef消费,它变成MutableRefObject

Screen Shot 2020-08-23 at 1 06 56 PM

我现在无法使用.current属性:

Screen Shot 2020-08-23 at 1 10 27 PM

@Jessidhia @osf2e你的建议在这里似乎不适用。

我不得不求助的解决方法:

        if (ref && (ref as RefObject<HTMLDivElement>).current) {
              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
              (ref as RefObject<
                HTMLDivElement
              >)!.current!.style.height = `${containerHeight}px`;
            }

使用 react-native-web,我不得不使用。

import {RefObject} from 'react';
// ...
const myRef = useRef() as RefObject<View>

我对Input元素的 Ref 有这个问题
所以我从useRef<HTMLDivElement>() -> useRef<HTMLInputElement>()切换,它工作正常

@joshribakoff也可以直接输入参数

export const Panel = React.forwardRef((props: PanelProps, ref: React.RefObject<HTMLDivElement>) => {

这样,您在访问 ref 时就不必进行类型转换。
但我仍然不明白为什么我们必须这样做......

此页面是否有帮助?
0 / 5 - 0 等级