如何基于TypeScript接口键限制字符串字面量的合法取值范围
TypeScript 基于接口约束字符串取值范围的实现方案
问题原因
你原有写法的问题在于:泛型参数的默认值是顶层联合类型,TypeScript 推导时会取不同联合项的属性交集,因此只能拿到所有 Context 下共有的 button 属性,自然无法识别 contact 独有的 button2 属性。
修正后的实现
通过三层嵌套映射类型逐层遍历所有合法组合,避免取不同层级属性的交集:
interface Events { "home": { "button": "press" }, "contact": { "button": "press", "button2": "press" | "longpress", } } type EventName<E = Events> = { // 遍历第一层所有上下文key [Context in Extract<keyof E, string>]: { // 遍历当前上下文下所有对象key [Object in Extract<keyof E[Context], string>]: { // 遍历当前对象下所有合法动作值 [Action in Extract<E[Context][Object], string>]: `${Context}-${Object}-${Action}` // 索引访问,取当前对象的所有动作拼接结果为联合 }[Extract<E[Context][Object], string>] // 索引访问,取当前上下文的所有对象拼接结果为联合 }[Extract<keyof E[Context], string>] // 索引访问,取所有上下文的拼接结果为最终联合 }[Extract<keyof E, string>]
效果验证
// 合法值正常通过 const works1: EventName = "home-button-press"; const works2: EventName = "contact-button-press"; const works3: EventName = "contact-button2-longpress"; // 非法值正常报错:home上下文不存在button2 const doesntWork: EventName = "home-button2-longpress";
实现原理
嵌套映射类型会独立推导每个上下文、对象、动作的合法组合,再通过索引访问把所有合法的拼接字符串聚合为联合类型,完全符合前序键值约束后续取值的要求。
内容的提问来源于stack exchange,提问作者Harry Payne
相关产品推荐
相关产品推荐

