如何让TypeScript根据函数参数值推断数组元素的具体映射类型?
如何让TypeScript根据函数参数值推断数组元素的具体映射类型?
我明白你的困扰——你希望TypeScript能根据传入的device参数值,自动将数组arr的类型收窄到对应的EventTypes成员类型,而不用类型断言或者事后再遍历数组检查一遍。其实核心问题在于TypeScript需要明确知道device的具体类型和数组类型之间的绑定关系,而通过泛型函数就能完美解决这个问题。
解决思路
把你的func函数改成泛型函数,让它接收一个泛型参数D(约束为GestureDevice)。这样TypeScript就能全程跟踪device的具体子类型,并且把数组arr的类型直接绑定到EventTypes[D]上。当你后续检查device的值时,TypeScript会自动收窄泛型参数D的类型,进而确定数组的具体元素类型。
修正后的代码
type GestureDevice = "key" | "pointer"; type EventTypes = { "key": KeyboardEvent; "pointer": PointerEvent; }; const k = (e: KeyboardEvent[]) => {} const p = (e: PointerEvent[]) => {} // 改为泛型函数,泛型D约束为GestureDevice const func = <D extends GestureDevice>(device: D, events: Event[]) => { // 数组类型直接绑定到EventTypes[D] const arr: Array<EventTypes[D]> = []; for (const e of events) { // isEventTypeOf的泛型会自动匹配D,确保e是EventTypes[D]类型 if (isEventTypeOf(device, e)) { arr.push(e); // 这里完全安全,不需要任何断言 } } // 检查device值时,TypeScript会自动收窄D的类型 if (device === "pointer") { p(arr); // 此时arr被推断为PointerEvent[],直接调用p即可 } else { k(arr); // 此时arr被推断为KeyboardEvent[],直接调用k即可 } } const isEventTypeOf = <D extends GestureDevice>(device: D, event: Event): event is EventTypes[D] => { if (device === "key") { return event instanceof KeyboardEvent; } else if (device === "pointer") { return event instanceof PointerEvent; } return false; }
为什么这样有效?
- 泛型参数
D和device参数的类型绑定在一起,TypeScript会全程跟踪D的具体类型。 - 当你检查
device === "pointer"时,TypeScript会把泛型参数D收窄为"pointer",因此EventTypes[D]就变成了PointerEvent,数组arr的类型自然就是PointerEvent[],完全符合p函数的参数要求。 - 你的
isEventTypeOf函数已经是泛型的,它会根据传入的device类型返回正确的类型谓词,确保只有符合类型的事件被推入数组,所以后续不需要再重复检查整个数组。
这样就彻底解决了你在第22行遇到的问题,既不需要类型断言,也不用做冗余的数组元素检查。
备注:内容来源于stack exchange,提问作者Aayla Secura
相关产品推荐
相关产品推荐

