将 useRef 与 TypeScript 一起使用的问题

Posted

技术标签:

【中文标题】将 useRef 与 TypeScript 一起使用的问题【英文标题】:Issue using useRef with TypeScript 【发布时间】:2020-11-17 01:10:39 【问题描述】:

我有以下代码;

App.tsx

export default function App() 
  const [canvasRef, canvasWidth, canvasHeight] = useCanvas();
  return (
    <div>
      <canvas
        ref=canvasRef
      />
    </div>
  )

useCanvas.ts

import  useRef, useEffect  from "react";

const canvasWidth = 1200;
const canvasHeight = 600;

export default function useCanvas() 
  const canvasRef = useRef<htmlCanvasElement>(null);
  return [canvasRef, canvasWidth, canvasHeight]

是的,这正是我的代码中的内容,但是,我在来自 Vscode 的 App.tsx 中收到以下错误;

(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string | React.RefObject<HTMLCanvasElement> | ((instance: HTMLCanvasElement | null) => void) | null | undefined
Type 'number | RefObject<HTMLCanvasElement>' is not assignable to type 'string | RefObject<HTMLCanvasElement> | ((instance: HTMLCanvasElement | null) => void) | null | undefined'.
  Type 'number' is not assignable to type 'string | RefObject<HTMLCanvasElement> | ((instance: HTMLCanvasElement | null) => void) | null | undefined'.ts(2322)
index.d.ts(143, 9): The expected type comes from property 'ref' which is declared here on type 'DetailedHTMLProps<CanvasHTMLAttributes<HTMLCanvasElement>, HTMLCanvasElement>'

任何建议将不胜感激。

【问题讨论】:

检查类似的问题,这可能会帮助你***.com/questions/33796267/… 【参考方案1】:
function useCanvas() 
  const canvasRef = useRef<HTMLCanvasElement>(null);
  return [canvasRef, canvasWidth, canvasHeight]

由于您没有为返回值指定类型,因此打字稿会推断它。在推断数组的类型时,打字稿会假定它是一个普通数组,而不是 tuple。

为简化起见,假设您要返回以下内容:

function () 
  return [1, 'a'];

Typescript 会推断类型为(number | string)[]。换句话说,一个任意长度的数组,其中每个元素都可以是字符串的数字。它不会推断类型为[number, string]。因此,如果您尝试与该数组的索引 0 进行交互,打字稿将无法告诉您它绝对是一个数字,只能告诉您它是一个数字或字符串。

所以你的第一个选择是给你返回的东西一个明确的类型。在我的简化案例中,它将是:

function () 
  const result: [number, string] = [1, 'a'];
  return result;


// or
function (): [number, string] 
  return [1, 'a'];


// or
function () 
  return [1, 'a'] as [number, string];

我不确定您的代码是否正确的类型,但您可以检查变量并找出答案。

另一种选择,可能是更简单的选择,是使用as const 来帮助 typescript 推断类型。 as const 告诉它这永远不会改变,因此它会将其视为元组而不是数组。

function useCanvas() 
  const canvasRef = useRef<HTMLCanvasElement>(null);
  return [canvasRef, canvasWidth, canvasHeight] as const;

【讨论】:

完美,谢谢!一开始我不确定这是否只是一个 linting 错误,但这更有意义。【参考方案2】:

你的自定义钩子的返回类型是(number | React.MutableRefObject&lt;HTMLCanvasElement&gt;)[],因为打字稿推断它返回一个包含这些类型的数组。这就是为什么 App.tsx 中的解构变量没有正确键入(如果将它们悬停,您会看到它们都是 number | React.MutableRefObject&lt;HTMLCanvasElement&gt; 类型)。

你需要的是使用一个元组来告诉 typescript 这个数组中到底包含什么。

您可以像这样将输入信息添加到您的自定义挂钩中:

import  useRef, useEffect, MutableRefObject  from "react";

const canvasWidth = 1200;
const canvasHeight = 600;

export default function useCanvas(): [MutableRefObject<HTMLCanvasElement>, number, number] 
  const canvasRef = useRef<HTMLCanvasElement>(null);
  return [canvasRef, canvasWidth, canvasHeight]

【讨论】:

以上是关于将 useRef 与 TypeScript 一起使用的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Typescript 中将 ref prop 和 useRef 与 Lottie 文件一起使用?

useRef TypeScript - 不可分配给类型 LegacyRef<HTMLDivElement>

React - useRef 与 TypeScript 和功能组件

如何将 React useRef 钩子与打字稿一起使用?

将 Typescript 与 Laravel 和 Vue.js 一起使用,导入不使其成为 Vue 组件?

如何使 typescript 与 Promise 一起使用?