TypeScript封装非空校验仍提示Object possibly undefined怎么办
问题描述
现有如下业务代码,封装checkCharts函数统一校验折线图、柱状图实例是否为undefined,避免多场景下重复编写相同判断逻辑:
function checkCharts( lineChart: InstanceType<typeof chart> | undefined, barChart: InstanceType<typeof chart> | undefined ) { if (!lineChart || !barChart) { console.warn( "No linechart found. Probably navigated away before this function ended" ); return false; } return true; } onMounted(async () => { await nextTick(); await setDatapoints(); if (!checkCharts(linechart.value, barchart.value)) return; linechart.value.update(); barchart.value.update(); });
实际使用时,即使经过checkCharts校验通过,TypeScript仍然抛出Object possibly undefined的类型错误。
问题原因
TypeScript的类型收窄能力默认仅在当前代码块上下文生效,不会自动识别跨函数的逻辑判断。checkCharts内部的非空校验逻辑对外层调用方是黑盒,TS编译器无法感知到经过函数判断后两个图表实例已经排除了undefined类型,因此会继续抛出类型错误。
解决方案
提供两种可落地的修复方案,优先推荐第二种,无TypeScript版本兼容问题,类型收窄100%生效:
- 方案1:将函数改造为类型守卫
通过类型谓词明确告知TS:当函数返回true时,传入的参数为非空的图表实例。注意该方案如果传入ref.value这类可变属性,部分TS版本下可能出现收窄失效,建议直接传入ref对象做判断:import type { Ref } from 'vue'; type ChartInstance = InstanceType<typeof chart>; function checkCharts( lineChart: Ref<ChartInstance | undefined>, barChart: Ref<ChartInstance | undefined> ): lineChart is Ref<ChartInstance> & barChart is Ref<ChartInstance> { if (!lineChart.value || !barChart.value) { console.warn( "No linechart found. Probably navigated away before this function ended" ); return false; } return true; } // 调用时直接传入ref实例,不需要取.value onMounted(async () => { await nextTick(); await setDatapoints(); if (!checkCharts(linechart, barchart)) return; // 此处TS自动收窄类型,无undefined报错 linechart.value.update(); barchart.value.update(); }); - 方案2:校验通过后返回收敛类型的实例(推荐)
不依赖TS的自动跨上下文收窄能力,将非空校验和实例返回绑定:校验不通过返回null,校验通过直接返回明确非空的实例元组,调用方直接使用返回的实例即可,完全规避类型收窄失效问题:type ChartInstance = InstanceType<typeof chart>; function checkCharts( lineChart: ChartInstance | undefined, barChart: ChartInstance | undefined ): [ChartInstance, ChartInstance] | null { if (!lineChart || !barChart) { console.warn( "No linechart found. Probably navigated away before this function ended" ); return null; } return [lineChart, barChart]; } onMounted(async () => { await nextTick(); await setDatapoints(); const instances = checkCharts(linechart.value, barchart.value); if (!instances) return; const [lineIns, barIns] = instances; // 两个实例类型明确为非空,无类型错误 lineIns.update(); barIns.update(); });
内容的提问来源于stack exchange,提问作者Ilijanovic
相关产品推荐
相关产品推荐

