TypeScript中自定义布尔型类型检查函数的类型推断问题解决
TypeScript类型检查封装后的类型推断问题解决方法
问题背景
我在开发一个简易计算器,原本使用以下可正常运行的函数进行首个操作数赋值(所有变量均为字符串,此为预期设计,并非当前问题核心):
function asignOperand(e: Event){ if (e instanceof MouseEvent && e.target instanceof HTMLButtonElement && e.target.dataset.key && operator === '' && preOperandB === ''){ preOperandA += e.target.dataset.key; } }
由于该检查逻辑在代码中重复出现,我将其封装为返回布尔值的函数:
function checkOperandsType(e: Event){ if (e instanceof MouseEvent && e.target instanceof HTMLButtonElement && e.target.dataset.key && operator === '' && preOperandB === ''){ return true; } else { return false; } }
但调用该函数后:
function asignOperand(e: Event){ if (checkOperandsType(e)){ preOperandA += e.target.dataset.key; } }
TypeScript报错:'e.target' is possibly 'null' 和 Property 'dataset' does not exist on type 'EventTarget'。
解决方案
核心问题是TypeScript无法从普通布尔返回值的函数中推断出类型收窄,以下是几种简洁且符合最佳实践的解决方式:
1. 使用类型谓词(Type Predicate)
让封装的检查函数明确告诉TypeScript:当返回true时,参数e的类型已经被收窄为特定类型。
function checkOperandsType(e: Event): e is MouseEvent & { target: HTMLButtonElement } { return ( e instanceof MouseEvent && e.target instanceof HTMLButtonElement && e.target.dataset.key && operator === '' && preOperandB === '' ); } function asignOperand(e: Event){ if (checkOperandsType(e)){ // TypeScript此时知道e是MouseEvent且target是HTMLButtonElement preOperandA += e.target.dataset.key; } }
e is MouseEvent & { target: HTMLButtonElement } 是类型谓词语法,它为函数添加了类型推断能力,确保后续代码能安全访问目标属性。
2. 使用断言函数(Assertion Function)
如果希望在检查不通过时直接抛出错误(而非跳过逻辑),可以用断言函数,它会让TypeScript认定后续代码的类型一定符合要求:
function assertOperandsType(e: Event): asserts e is MouseEvent & { target: HTMLButtonElement } { const isValid = ( e instanceof MouseEvent && e.target instanceof HTMLButtonElement && e.target.dataset.key && operator === '' && preOperandB === '' ); if (!isValid) { throw new Error('当前事件或状态不允许赋值操作数'); } } function asignOperand(e: Event){ assertOperandsType(e); // 断言通过后,TypeScript确认类型合法 preOperandA += e.target.dataset.key; }
3. 简化内联检查(无需封装函数)
如果只是想减少重复书写,也可以直接在函数内提取目标元素,一次性完成类型检查:
function asignOperand(e: Event){ const target = e.target; if ( e instanceof MouseEvent && target instanceof HTMLButtonElement && target.dataset.key && operator === '' && preOperandB === '' ) { preOperandA += target.dataset.key; } }
这种方式无需额外封装,TypeScript能正确识别变量target的类型收窄,同时减少重复的e.target调用。
内容的提问来源于stack exchange,提问作者veet
相关产品推荐
相关产品推荐

