【问题标题】:Type error: Type 'boolean | (() => void)' is not assignable to type 'MouseEventHandler<HTMLButtonElement> | undefined'类型错误:类型'boolean | (() => void)' 不可分配给类型 'MouseEventHandler<HTMLButtonElement> |不明确的'
【发布时间】:2021-10-12 13:26:34
【问题描述】:

我正在尝试在 NextJS 应用程序中播放音频,并且正在使用 TypeScript 编写代码。 我的onClick() 在开发环境中工作得非常好,这意味着当我做npm run dev 时。

<button onClick ={toggle}> {playing ? "Pause" : "Play"</button>

但是当我尝试做npm build 时,我收到了这个错误:

输入错误:输入'boolean | (() => void)' 不可分配给类型 'MouseEventHandler |不明确的'。 类型 'false' 不可分配给类型 'MouseEventHandler |未定义'。

在阅读了一堆关于 Stack Overflow 的问题后,我发现 onClick() 不期望 void 是 toggle 函数在这种情况下返回的,所以我做了:

<button onClick={() => toggle}> {playing ? "Pause" :"Play</button>

上述更改后,分配错误消失了,但是当我运行应用程序时,播放按钮不再起作用。 我愿意接受您对代码的任何其他建议。

这里是完整的代码:

const useAudio = (url: string) => {
  const audio = useRef<HTMLAudioElement | undefined>(
    typeof Audio !== "undefined" ? new Audio(url) : undefined
  );
  
  const [playing, setPlaying] = useState(false);

  const toggle = () => setPlaying(!playing);
  //const toggle = setPlaying(!playing);

  useEffect(() => {
      playing ? audio.current?.play() : audio.current?.pause();
  }, [playing]);

  useEffect(() => {
    audio.current?.addEventListener('ended', () => setPlaying(false));
    return () => {
      audio.current?.removeEventListener('ended', () => setPlaying(false));
    };
  }, []);

  return [playing, toggle];
};

const NFT = ({ baseUri, metaId, url }: { baseUri: string; metaId: string; url: string }) => {
  const [metadata, setMetadata] = useState<{[key: string]: string} | null>(null)

  const fetchMetadata = async (url: string) => {
    const response = await fetch(url)
    const result = await response.json()

    if (!result) return

    setMetadata(result)
  }

  if(url) {
    var [playing, toggle] = useAudio(url);
  }

  useEffect(() => {
    fetchMetadata(`${baseUri}/${metaId}`)
  }, [])

  if (!metadata) return null

  return (
    <div className="w-full md:w-1/2 lg:w-1/3 p-3 mb-4">
      <div className="h-96">
        <div className="relative items-center min-h-full">
          <a href="#">
            <Image
              alt={metadata[MetadataField.Title]}
              src={metadata[MetadataField.Media]}
              layout="fill"
              objectFit="contain"
            />
          </a>
        </div>
         {url &&
          <button onClick ={toggle}> {playing ? "Pause" : "Play"} </button>
         }
      </div>
    </div>
  )
}

【问题讨论】:

  • 与您的类型错误没有直接关系,但您不应该有条件地调用您的自定义 useAudio 钩子,这违反了 Rules of Hooks

标签: reactjs typescript react-hooks onclick next.js


【解决方案1】:

来自react-typescript-cheatsheet

如果您在自定义 Hook 中返回一个数组,则需要避免类型推断,因为 TypeScript 会推断联合类型(当您实际上希望数组的每个位置有不同的类型时)。

你需要使用const assertions

const useAudio = (url: string) => {
  const audio = useRef<HTMLAudioElement | undefined>(typeof Audio !== 'undefined' ? new Audio(url) : undefined);
  const [playing, setPlaying] = useState(false);
  const toggle = () => setPlaying(!playing);

  useEffect(() => {
    playing ? audio.current?.play() : audio.current?.pause();
  }, [playing]);

  useEffect(() => {
    audio.current?.addEventListener('ended', () => setPlaying(false));
    return () => {
      audio.current?.removeEventListener('ended', () => setPlaying(false));
    };
  }, []);

  return [playing, toggle] as const;
};

见下例:

function test() {
  return [true, () => {}];
}

const [isOk, func] = test(); 

func();  // error  

test函数的返回类型是TypeScript推断的联合类型(boolean | (() =&gt; void))[]。调用func()会报错:

This expression is not callable.
  Not all constituents of type 'boolean | (() => void)' are callable.
    Type 'false' has no call signatures.ts(2349)

解决方案一:const assertions

function test() {
  return [true, () => {}] as const
}

这将推断为[boolean, () =&gt; void] 而不是(boolean | (() =&gt; void))[]

解决方案 2:显式声明 test 的返回类型

function test(): [boolean, () => void] {
  return [true, () => {}];
}

此外,您不能有条件地使用钩子,它会破坏Rules of Hooks

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-24
    • 1970-01-01
    • 2019-01-29
    • 2017-06-29
    • 1970-01-01
    • 2020-07-22
    • 1970-01-01
    • 2019-01-04
    相关资源
    最近更新 更多