You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3组合式API中Template Refs的TypeScript空值处理最佳实践

问题

我正在开发一个使用Vue3组合式API与TypeScript的项目,第一步是通过HTMLCanvasElement渲染足球场。为了在<script>标签中访问其属性,我为它设置了Template Ref,并按照Vue文档声明为const canvas = ref<HTMLCanvasElement | null>(null)。但后续大量代码因canvas可能为null出现TypeScript报错。

我的疑问是:应当在所有canvas.value后添加可选链?(如canvas.value?.width),还是在每个方法开头添加if判断canvas.value不为null?

以下是我的TS代码,错误出现在render方法的前3行:

const canvas = ref<HTMLCanvasElement | null>(null);

function fitToContainer(canvas : HTMLCanvasElement){
    canvas.width  = canvas.offsetWidth;
    canvas.height  = canvas.offsetHeight;
}

function render(ctx: CanvasRenderingContext2D) {
    // Adjusting the canvas to the right dimenstions
    fitToContainer(canvas.value);
    const canvasWidth = canvas.value.width;
    const canvasHeight = canvas.value.height;

    // ---------------- FILL FIELD WITH COLOR ----------------
    ctx.fillStyle = "#3bad59";
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);

    // ---------------- DRAW LINES ----------------
}
解决方案

两种方式的对比

  • 可选链?.:代码写法更简洁,但存在隐患——如果canvas.value为null,canvasWidth、canvasHeight会变成undefined,后续依赖这些变量的运行时代码大概率会抛出Cannot read properties of undefined错误,而且TypeScript仍会提示变量可能为undefined,需要额外处理。
  • 开头加if判断:能一次性排除null场景,TypeScript会自动收窄canvas.value的类型为HTMLCanvasElement,后续代码无需再重复处理null情况,逻辑更安全,也能减少类型提示的困扰。

优化后的代码

推荐在render方法开头先判断canvas.value是否存在,不存在直接终止执行,避免后续报错:

const canvas = ref<HTMLCanvasElement | null>(null);

function fitToContainer(canvas : HTMLCanvasElement){
    canvas.width  = canvas.offsetWidth;
    canvas.height  = canvas.offsetHeight;
}

function render(ctx: CanvasRenderingContext2D) {
    // 先判断canvas是否挂载完成,未完成直接终止
    if (!canvas.value) return;

    // Adjusting the canvas to the right dimenstions
    fitToContainer(canvas.value);
    const canvasWidth = canvas.value.width;
    const canvasHeight = canvas.value.height;

    // ---------------- FILL FIELD WITH COLOR ----------------
    ctx.fillStyle = "#3bad59";
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);

    // ---------------- DRAW LINES ----------------
}

补充说明:如果render是在Vue的onMounted等生命周期钩子中调用,理论上canvas.value已经挂载完成不为null,但TypeScript无法识别这一上下文,所以仍需手动加判断;若你能100%确认canvas.value不会为null,也可以用非空断言!(如canvas.value!),但这种写法风险较高,仅在场景明确时使用。

内容的提问来源于stack exchange,提问作者Alexandru Lolea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:56:03