TypeScript 3.8.3 中字面量联合类型的自动补全实现求助
TypeScript 3.8.3 中字面量联合类型的自动补全实现求助
太懂你这种被旧TS版本卡脖子的无奈了!升级不了版本又要实现自动补全,确实头疼。咱们先理清楚核心问题:TS 3.8.3对联合类型的处理逻辑和4.7+的高版本差异很大,那些在高版本里生效的string & {}这类「破折联合」技巧,在3.8里根本起不到保留字面量补全的作用——编译器还是会把字面量联合和string类型合并成单一的string,直接吃掉了补全提示。
先把你的问题代码贴出来方便对照:
type ChannelEventPayloadMap = Record<string, Record<string, any>> type ChannelAutocomplete<ChannelMap extends ChannelEventPayloadMap> = | keyof ChannelMap | (string & {}) | RegExp class Listener<ChannelMap extends ChannelEventPayloadMap> { listen<C extends ChannelAutocomplete<ChannelMap>>(suggestions: C) {} } const listener = new Listener<{ chan: { ev: number }; chan2: { ev: boolean } }>() listener.listen("") // 在v3.8.3里无法正常补全,但v4.7.4+可以
你试过的Record<never, never>、带品牌属性的字符串类型这些方法,本质都是高版本TS才支持的类型提示技巧,3.8.3的编译器还没适配这种逻辑。针对3.8.3,最可靠的解决方案是用函数重载替代联合类型,因为重载在旧版本TS里对自动补全的支持更直接:
type ChannelEventPayloadMap = Record<string, Record<string, any>> class Listener<ChannelMap extends ChannelEventPayloadMap> { // 重载1:匹配已知的channel键,提供自动补全提示 listen(suggestions: keyof ChannelMap): void; // 重载2:允许传入任意字符串 listen(suggestions: string): void; // 重载3:允许传入正则表达式 listen(suggestions: RegExp): void; // 实际实现:处理所有允许的类型 listen(suggestions: keyof ChannelMap | string | RegExp): void {} } const listener = new Listener<{ chan: { ev: number }; chan2: { ev: boolean } }>() listener.listen("") // 现在在v3.8.3里应该能正常提示"chan"、"chan2",同时支持任意字符串/RegExp
为什么这个方法在3.8.3里有效?因为TS的重载解析会优先匹配最具体的类型——当用户输入时,编译器会先把keyof ChannelMap的字面量作为候选提示,同时也允许用户输入不符合字面量的字符串或正则,完全满足你的需求。
如果你还是想用类型别名的方式尝试,也可以试试这个适配3.8.3的写法,但效果可能不如重载稳定:
type LiteralUnion<T extends string> = T | string; type ChannelAutocomplete<ChannelMap extends ChannelEventPayloadMap> = LiteralUnion<keyof ChannelMap & string> | RegExp;
不过亲测在3.8.3里,单纯的类型联合还是容易被折叠成string | RegExp,所以重载是更稳妥的选择。
备注:内容来源于stack exchange,提问作者Nikola-Milovic
相关产品推荐
相关产品推荐

