使用动态运算符时无法正确为JSON Logic编写TypeScript类型
解决json-logic-js类型定义中动态运算符的TypeScript编译错误
问题原因
当使用动态属性名创建RulesLogic对象时,TypeScript会将对象推断为{ [x: string]: ... }这类索引签名类型,但RulesLogic是由所有合法运算符对应的单属性对象组成的联合类型(例如{ '==': Expression[] } | { '>=': Expression[] } | ... | { log: JsonLogicLogOptions })。索引签名类型无法匹配联合类型的结构,因此触发类型不兼容错误。
解决方案
1. 类型断言(快速解决)
直接将动态创建的对象断言为RulesLogic,前提是你能确保运算符属于合法的ReservedOperations集合:
const op: ReservedOperations[] = ['==','>=','<=','==='] const dynamicOperator = op[1] const dynamicRule: RulesLogic = { [dynamicOperator]: [{var:'one'},1] } as RulesLogic;
2. 类型守卫(更安全)
创建类型守卫函数,让TypeScript确认动态运算符的合法性,避免非法运算符的隐患:
import { ReservedOperations, RulesLogic } from 'json-logic-js'; function isValidOperator(op: string): op is ReservedOperations { // 枚举所有ReservedOperations包含的运算符 const validOps: ReservedOperations[] = [ '==', '===', '!=', '!==', '>', '>=', '<', '<=', 'and', 'or', 'not', 'if', '?:', 'switch', 'case', 'null', 'undefined', '!!', 'log', 'var', 'missing', 'missing_some', 'map', 'filter', 'reduce', 'all', 'none', 'some' ]; return validOps.includes(op as ReservedOperations); } // 使用示例 const op: ReservedOperations[] = ['==','>=','<=','==='] const dynamicOperator = op[1]; if (isValidOperator(dynamicOperator)) { const dynamicRule: RulesLogic = { [dynamicOperator]: [{var:'one'},1] }; // 这里可以安全使用dynamicRule }
3. 泛型函数优化(适用于工厂函数场景)
针对你的工厂函数场景,通过泛型约束运算符类型,再结合类型断言解决:
import { RulesLogic } from 'json-logic-js'; const createRulesLogic = <Op extends '==' | '!='>(operation: Op): RulesLogic => ({ [operation]: [{var:'one'},1] } as Record<Op, unknown> as RulesLogic);
补充说明
报错中提到的Property 'log' is missing是因为RulesLogic联合类型包含了JsonLogicLog类型(对应log运算符),而动态创建的对象显然没有log属性。本质还是TS无法确认动态属性名属于联合类型中的某一个成员,导致无法匹配类型。
内容的提问来源于stack exchange,提问作者Adam Jenkins
相关产品推荐
相关产品推荐

