Definitelytyped: [@types/react] el tipo de retorno de useRef choca con el tipo de prop de referencia

Creado en 19 may. 2019  ·  12Comentarios  ·  Fuente: 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'.

Comentario más útil

Una solución un poco más ordenada es establecer initialValue en nulo en la llamada a la función useRef

const componentRef = useRef<HTMLDivElement>(null);

esto asegura que componentRef = HTMLDivElement | null que es lo que espera la referencia de apoyo en lugar de HTMLDivElement | undefined .

Todos 12 comentarios

EDIT 2: Ignore mi solución, use la siguiente :)

Actualmente tengo el mismo problema, ¿ya has encontrado una solución por casualidad?

EDITAR: ahora estoy usando esta solución, ciertamente no tan bonita:

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

Encontrado aquí: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/28884#issuecomment -471341041

Una solución un poco más ordenada es establecer initialValue en nulo en la llamada a la función useRef

const componentRef = useRef<HTMLDivElement>(null);

esto asegura que componentRef = HTMLDivElement | null que es lo que espera la referencia de apoyo en lugar de HTMLDivElement | undefined .

@ shane935 me ha alegrado el día, señor 🙌🏻

Me parece que undefined debería agregarse a RefObject<T>.current como:

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

asi se lee

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

No es un error, está detectando un error de tipeo legítimo.

Para obtener más detalles, consulte https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38228#issuecomment -529749802

Tal como dice @Jessidhia , no es un error, tal vez deberías escribir así.

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;

No estoy seguro de que esto solucione el problema de todos, y no soy un experto en estas cosas, pero después de mirar los tipos de lo que estaba pasando como referencia y el tipo de referencia real del componente al que estaba pasando la referencia , parecía que tenía las interfaces incorrectas.

Inicialmente tenía una interfaz de accesorios como esta para el componente receptor:

type TextboxProps = CustomProps & React.HTMLProps<HTMLInputElement>

que cambié a:

type TextboxProps = CustomProps & React.HTMLAttributes<HTMLInputElement>

el error de tipeo luego desapareció.

No voy a fingir que sé más de lo que sé, pero al observar los tipos de la interfaz HTMLProps y el tipo de función React.forwardRef(), puede ver que está usando RefAttributes. Justo encima de eso, puede ver ClassAttributesescribe eso HTMLPropsse está extendiendo, de la cual define el LegacyReftipo que creo que estaba causando mi problema de escritura.

Parece que este proyecto tiene 3 sobrecargas por useRef() , ¿necesitamos los 3? Parece que el caso useRef<T>(null) es el que los desarrolladores usarán la mayor parte del tiempo.

    function useRef<T>(initialValue: T): MutableRefObject<T>;
    function useRef<T>(initialValue: T|null): RefObject<T>;
    function useRef<T = undefined>(): MutableRefObject<T | undefined>;
  1. ¿Cuál es el caso de uso esperado de las dos sobrecargas mutables?
  2. ¿Hay alguna otra forma en que esto pueda ser compatible para que los usuarios puedan encontrar más fácilmente la sobrecarga "correcta"?

Tengo RefObject :

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

Lo paso a mi componente Panel como accesorio ref :

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

Intento consumir con forwardRef , se convierte en MutableRefObject :

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

Ahora no puedo consumir la propiedad .current :

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

@Jessidhia @osf2e su sugerencia no parece aplicable aquí.

La solución a la que he tenido que recurrir:

        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`;
            }

Usando react-native-web, tuve que usar.

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

Tuve este problema con una Ref para un elemento Input
Así que cambié de useRef<HTMLDivElement>() -> useRef<HTMLInputElement>() y funcionó bien

@joshribakoff También puede escribir los parámetros directamente

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

De esa manera, no debería tener que encasillar al acceder a su ref.
Pero todavía no entiendo por qué tenemos que hacer esto...

¿Fue útil esta página
0 / 5 - 0 calificaciones