如何不使用类型断言判断字符串是否属于TypeScript字符串字面量类型
方案1:封装通用工具函数(最常用,推荐)
你可以把类型断言收敛到通用工具层,仅需编写一次即可全场景复用,业务代码不会出现任何断言:
// 全局通用工具,仅需定义一次 function createConstArrayGuard<T extends string>(arr: readonly T[]) { return (value: string): value is T => { return (arr as readonly string[]).includes(value); }; }
业务侧使用方式和你原来的习惯完全一致,不需要额外修改枚举定义:
const supportedLanguageTags = [ "de-at", "de-ch", "de-de", "en-gb", "en-us", ] as const; type LanguageTag = typeof supportedLanguageTags[number]; // 直接生成类型守卫函数,无任何业务侧断言 const isSupportedLanguageTag = createConstArrayGuard(supportedLanguageTags);
方案2:自动生成映射对象(无任何断言,适合大数量枚举场景)
如果你完全不想出现任何类型断言,又不想手写无意义的对象占位值,可以直接从数组自动生成映射对象:
const supportedLanguageTags = [ "de-at", "de-ch", "de-de", "en-gb", "en-us", ] as const; type LanguageTag = typeof supportedLanguageTags[number]; // 自动从数组生成映射表,不需要手写每个属性的占位值 const supportedLangMap = Object.fromEntries( supportedLanguageTags.map(tag => [tag, true]) ) as Record<LanguageTag, boolean>; function isSupportedLanguageTag(tag: string): tag is LanguageTag { return tag in supportedLangMap; }
这个方案的优势是查找性能为O(1),当枚举值数量成百上千时,性能远高于数组includes的O(n)查找。
补充说明
受限于TypeScript目前的类型系统设计,Array.prototype.includes的参数要求必须是数组元素类型的子类型,因此对于as const生成的窄类型只读数组,直接传入string类型的参数调用includes必然会触发类型报错,必须通过类型断言拓宽数组类型才能正常调用。把断言收敛到通用工具中是目前生产环境最常用的最优解法,不会带来额外的业务侧心智负担。
内容的提问来源于stack exchange,提问作者Krisztián Balla
相关产品推荐
相关产品推荐

