React&TS:能否用区分联合类型处理输入框与文本域共用处理器?
用区分联合类型实现HTMLInputElement和HTMLTextAreaElement共用事件处理器
完全可以通过区分联合类型(Discriminating Unions)实现这个需求,而且能让类型推导更精准、代码更安全,无需依赖宽泛的类型断言。
核心思路
区分联合类型的关键是利用两个元素的字面量类型公共属性作为判别式。对于HTMLInputElement和HTMLTextAreaElement,它们的tagName属性正好满足:input元素的tagName固定为"INPUT",textarea元素的tagName固定为"TEXTAREA",TypeScript可以通过这个属性自动收窄类型。
代码示例(原生TS)
// 定义带判别式的联合类型 type InputOrTextArea = | HTMLInputElement & { tagName: 'INPUT' } | HTMLTextAreaElement & { tagName: 'TEXTAREA' }; // 共用事件处理器 function handleInput(e: Event) { const target = e.target as InputOrTextArea; switch (target.tagName) { case 'INPUT': // 此处target自动推断为HTMLInputElement,可直接访问专属属性 console.log('输入框值:', target.value, '输入类型:', target.type); break; case 'TEXTAREA': // 此处target自动推断为HTMLTextAreaElement,可直接访问专属属性 console.log('文本域值:', target.value, '行数:', target.rows); break; } } // 绑定到元素 const input = document.querySelector('input'); const textarea = document.querySelector('textarea'); input?.addEventListener('input', handleInput); textarea?.addEventListener('input', handleInput);
React场景下的示例
如果是React表单事件,逻辑完全一致:
import { ChangeEvent } from 'react'; function handleInputChange(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) { const target = e.target; if (target.tagName === 'INPUT') { console.log('输入框类型:', target.type); } else if (target.tagName === 'TEXTAREA') { console.log('文本域行数:', target.rows); } // 通用逻辑:获取输入值 console.log('当前输入值:', target.value); } // 在组件中使用 function Form() { return ( <div> <input type="text" onChange={handleInputChange} /> <textarea rows={3} onChange={handleInputChange} /> </div> ); }
优势对比
相比之前扩展类型的方案,这种方式的好处在于:
- 类型推导自动完成,无需手动断言类型
- 分支内可直接访问对应元素的专属属性,不会出现类型报错
- 代码逻辑更清晰,通过判别式明确区分两种元素的处理逻辑
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

