TypeScript中如何复用动态参数类型约束函数其他参数
TypeScript 类型精准约束实现方案
核心思路是通过const类型修饰符锁定传入事件数组的字面量类型,将数组成员的联合类型直接映射到回调函数的事件类型参数上,不需要额外手动指定泛型,TS会自动推导匹配。
最终实现代码(TS 5.0+ 推荐写法)
不需要调用方额外加类型断言,自动推导传入的事件类型集合:
const addListeners = <const E extends keyof HTMLElementEventMap>( events: readonly E[], htmlElement: HTMLElement, handler: (eventType: E) => void ): void => { events.forEach(eventName => { htmlElement.addEventListener(eventName, () => { handler(eventName); // 如果你确实需要把绑定的元素传入回调,把上行改为handler(eventName, htmlElement) // 同步把handler的类型定义改为 (eventType: E, el: HTMLElement) => void 即可 }); }); };
低版本TS兼容写法(TS 5.0以下)
低版本不支持const类型参数,需要调用时给事件数组加as const锁定字面量类型:
const addListeners = <E extends keyof HTMLElementEventMap>( events: readonly E[], htmlElement: HTMLElement, handler: (eventType: E) => void ): void => { events.forEach(eventName => { htmlElement.addEventListener(eventName, () => { handler(eventName); }); }); }; // 调用示例 const btn = document.createElement('button'); addListeners(['click', 'touchstart'] as const, btn, eventType => { console.log(`Handling ${eventType} event`); });
实现效果
调用函数时,回调参数eventType的类型会被严格收窄为你传入的事件数组的成员联合类型:
- 合法操作:判断
eventType === 'click'、eventType === 'touchstart'时TS会正确识别分支类型 - 非法操作:如果判断
eventType === 'scroll'这类不在传入事件集合里的值,TS会直接抛出类型错误
原写法问题说明
- 原泛型没有加const修饰,TS会默认把传入的数组类型拓宽为宽泛的事件类型联合,无法和传入的具体成员绑定
- 原handler的参数直接标注为
string,完全丢失类型约束,无法做自动收窄 - 原实现中给handler传入了
htmlElement作为第二个参数,但和给出的调用示例参数个数不匹配,容易引发运行时和类型定义不一致的问题
内容的提问来源于stack exchange,提问作者Erik Booij
相关产品推荐
相关产品推荐

