TypeScript结合枚举使用条件类型时,实现函数返回值报错如何解决?
问题原因
这是TypeScript当前类型系统的固有特性导致的:泛型条件类型在函数内部不会根据分支逻辑自动窄化。
你用UIConfigurationEntitySuffix<T>作为返回值类型时,即便你通过switch语句明确判断了输入参数uiConfigurationType的具体枚举值,TS也无法将泛型T和当前分支的枚举值绑定,因此无法识别出你返回的字符串字面量正好对应UIConfigurationEntitySuffix<T>的最终类型,就会触发类型不匹配的报错。
解决方案
方案1:使用函数重载(改动最小)
通过函数重载分开定义对外的类型签名和内部实现,即可规避这个问题,调用时的类型推导也完全不受影响:
// 重载签名:对外暴露的类型定义 function getUIConfigurationEntitySuffix(uiConfigurationType: UIConfigurationType.DisplayTableFields): "display-table-fields"; function getUIConfigurationEntitySuffix(uiConfigurationType: UIConfigurationType.FormFields): "form-fields"; function getUIConfigurationEntitySuffix(uiConfigurationType: UIConfigurationType.MainAttributes): "main-attributes"; function getUIConfigurationEntitySuffix(uiConfigurationType: UIConfigurationType.SearchAttributes): "search-attributes"; // 实现签名:内部使用的宽松类型 function getUIConfigurationEntitySuffix(uiConfigurationType: UIConfigurationType) { switch (uiConfigurationType) { case UIConfigurationType.DisplayTableFields: return "display-table-fields"; case UIConfigurationType.FormFields: return "form-fields"; case UIConfigurationType.MainAttributes: return "main-attributes"; case UIConfigurationType.SearchAttributes: return "search-attributes"; default: throw new Error(`Unknown uiConfigurationType: ${uiConfigurationType}`); } }
方案2:用映射表重构(更易维护)
直接将枚举和后缀的映射关系统一定义,无需手写冗长的条件类型,也不会触发类型报错,后续新增枚举值只需要修改映射表即可:
enum UIConfigurationType { DisplayTableFields = "display-table-field", FormFields = "form-field", MainAttributes = "main-attribute", SearchAttributes = "search-attribute", } // 统一定义映射关系,同时给类型和运行时使用 const UI_CONFIG_SUFFIX_MAP = { [UIConfigurationType.DisplayTableFields]: "display-table-fields", [UIConfigurationType.FormFields]: "form-fields", [UIConfigurationType.MainAttributes]: "main-attributes", [UIConfigurationType.SearchAttributes]: "search-attributes", } as const; // 直接从映射表推导类型,不需要手写条件类型 type UIConfigurationEntitySuffix<T extends UIConfigurationType> = typeof UI_CONFIG_SUFFIX_MAP[T]; // 函数直接查表返回,逻辑简单无类型报错 function getUIConfigurationEntitySuffix<T extends UIConfigurationType>( uiConfigurationType: T ): UIConfigurationEntitySuffix<T> { return UI_CONFIG_SUFFIX_MAP[uiConfigurationType]; }
如果暂时不想改动现有结构,也可以在每个return的字符串后加as UIConfigurationEntitySuffix<T>类型断言绕过检查,但是不推荐这种写法,会丧失类型校验能力。
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

