网站搜索

reactjs - React - 类型 'number | MutableRefObject' 不能分配给类型 'LegacyRef'


当我想给主元素添加引用时,出现以下错误。

错误

Type 'number | MutableRefObject<any>' is not assignable to type 'LegacyRef<HTMLElement>'.
  Type 'number' is not assignable to type 'LegacyRef<HTMLElement>'

如何修复它?

index.tsx

import React from "react";
import ReactDOM from "react-dom";
import useScrollPercentage from "./useScrollPercentage";

// reset styles
Object.assign(document.body.style, {
  overflow: "hidden",
  margin: "0"
});

function App() {
  const [scrollRef, scrollPercentage] = useScrollPercentage();

  return (
    // attach scrollRef to scroll container
    <main ref={scrollRef} style={{ height: "100vh", overflowY: "scroll" }}>
      {/* Simulate overflowing content */}
      <div style={{ height: 3000 }} />

      {/* Display scroll percentage */}
      <h1 style={{ position: "fixed", top: 10, left: 10 }}>
        {`${scrollPercentage}%`}
      </h1>
    </main>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

useScrollPercentage.js

import { useRef, useState, useEffect } from "react";

export default function useScrollPercentage() {
  const scrollRef = useRef(null);
  const [scrollPercentage, setScrollPercentage] = useState(NaN);

  const reportScroll = e => {
    setScrollPercentage(getScrollPercentage(e.target));
  };

  useEffect(
    () => {
      const node = scrollRef.current;
      if (node !== null) {
        node.addEventListener("scroll", reportScroll, { passive: true });
        if (Number.isNaN(scrollPercentage)) {
          setScrollPercentage(getScrollPercentage(node));
        }
      }
      return () => {
        if (node !== null) {
          node.removeEventListener("scroll", reportScroll);
        }
      };
    },
    [scrollPercentage]
  );

  return [scrollRef, Number.isNaN(scrollPercentage) ? 0 : scrollPercentage];
}

function getScrollPercentage(element) {
  if (element === null) {
    return NaN;
  }
  const height = element.scrollHeight - element.clientHeight;
  return Math.round((element.scrollTop / height) * 100);
}

Codesandbox
https://codesandbox.io/s/scroll-percentage-hook-forked-6bcyw?file=/src/index.tsx

答案#1

export default function useScrollPercentage() {
  // ...
  return [scrollRef, Number.isNaN(scrollPercentage) ? 0 : scrollPercentage];
}

由于你没有给出明确的返回类型,TypeScript 必须进行推断。它会假设这是一个数组,而不是元组,因此数组的类型是 (MutableRefObject<any> | number)[],因为它包含了 ref 对象和数字。这个类型没有关于数组中各元素位置的任何信息,因此在 App 中,不清楚 scrollRef 是 ref 还是数字。

如果你希望类型是一个元组 [MutableRefObject<any>, number],你需要自己为它指定类型。你可以这样做:

export default function useScrollPercentage(): [MutableRefObject<any>, number] {

或者你可以继续使用类型推断,但使用 as const 提示 TypeScript,这样它会推断出更严格的类型:

return [scrollRef, Number.isNaN(scrollPercentage) ? 0 : scrollPercentage] as const;