TypeScript:如何在类型层面断言字符串为枚举有效值?
TypeScript枚举字符串推断问题解决方法
问题背景
定义了如下枚举:
enum MimeType { VideoMP4 = 'video/mp4', VideoQuicktime = 'video/quicktime', }
同时有一个依赖枚举的泛型类型:
type Something<M extends MimeType> = { type: M; // 其他自定义结构 };
需求是实现一个泛型函数createSomething,从形如"前缀:枚举值"的输入字符串中,推断出对应的枚举类型,并返回Something<具体枚举成员>类型。
尝试的两种写法均存在问题:
- 第一种写法始终返回
never,因为字符串字面量无法直接匹配枚举类型:
function createSomething<const V extends `${string}:${MimeType}`>(value: V): V extends `${string}:${infer M}` ? M extends MimeType ? Something<M> : never : never;
比如'video/mp4' extends MimeType结果为false,但'video/mp4' extends MimeType[keyof MimeType]结果为true,但后者无法满足Something的泛型约束。
- 第二种写法中,传入具体值时
M会被推断为整个MimeType联合类型,无法得到具体枚举成员:
function createSomething<M extends MimeType, const V extends `${string}:${M}`>(value: V): Something<M>;
解决方案
方案1:通过Extract将字符串字面量映射为枚举类型
调整条件类型,先判断字符串是否属于枚举值集合,再用Extract提取对应的枚举成员:
// 类型定义 function createSomething<const V extends `${string}:${MimeType[keyof MimeType]}`>( value: V ): V extends `${string}:${infer M}` ? M extends MimeType[keyof MimeType] ? Something<Extract<MimeType, M>> : never : never; // 实现逻辑 function createSomething(value: string) { const [, mimeTypeStr] = value.split(':'); return { type: mimeTypeStr as MimeType }; }
测试验证:
const result = createSomething('demo:video/mp4'); // result 的类型为 Something<MimeType.VideoMP4>
方案2:调整泛型参数顺序优化推断
先推断具体的枚举值字符串,再关联到枚举类型:
// 类型定义 function createSomething<const MStr extends MimeType[keyof MimeType], const V extends `${string}:${MStr}`>( value: V ): Something<Extract<MimeType, MStr>>; // 实现逻辑 function createSomething(value: string) { const [, mimeTypeStr] = value.split(':'); return { type: mimeTypeStr as MimeType }; }
原理说明
- TypeScript的枚举类型是成员标识符与成员值的联合类型,字符串字面量属于枚举值的集合(
MimeType[keyof MimeType]),而非枚举类型本身。 Extract<MimeType, M>的作用是从MimeType枚举中筛选出值等于M的成员,将字符串字面量转换为对应的枚举类型,从而满足Something的泛型约束。
内容的提问来源于stack exchange,提问作者WoodyWoodsta
相关产品推荐
相关产品推荐

