如何在TypeScript中实现动态JSON转逻辑公式的函数?
修正TypeScript递归方法:将动态JSON转换为逻辑公式
需求说明
需要实现一个TypeScript递归方法,将符合以下接口结构的动态JSON转换为逻辑公式:
类型定义
export interface Regole { descrizioneRegola: string; naturaGiuridica: string; regolaPerCollegamento: RegolaPerCollegamento[]; or?: OperatoreLogico; and?: OperatoreLogico; not?: OperatoreLogico; } export interface OperatoreLogico { regolaPerCollegamento?: RegolaPerCollegamento[]; or?: OperatoreLogico; and?: OperatoreLogico; not?: OperatoreLogico; } export interface RegolaPerCollegamento { tipoCollegamentoEsistente?: number; tipoCollegamento?: number; quantita?: string; minimo?: number; massimo?: number; esattamente?: number; }
转换规则
and运算符:将数组内的对象用&&连接or运算符:将数组内的对象用||连接not运算符:在子结果前添加!- 外层运算符连接内层计算结果,多子项自动添加括号保证逻辑优先级
示例
输入JSON:
let json: OperatoreLogico = { "or": { "and": { "regolaPerCollegamento": [ { "tipoCollegamentoEsistente": 115, "quantita": "NESSUNO" }, { "tipoCollegamentoEsistente": 118, "quantita": "NESSUNO" } ] }, "or": { "regolaPerCollegamento": [ { "tipoCollegamento": 115, "minimo": 1 }, { "tipoCollegamento": 118, "minimo": 1 } ] } } }
期望输出:
({tipoCollegamentoEsistente: 115, quantita: "NESSUNO"} && {tipoCollegamentoEsistente: 118, quantita: "NESSUNO"}) || ({tipoCollegamento: 115, minimo: 1} || {tipoCollegamento: 118, minimo: 1})
原代码问题分析
原递归方法存在以下关键问题:
- 递归调用的返回值未被收集,直接返回空字符串导致结果丢失
initial和result参数维护逻辑混乱,未正确传递运算符上下文- 规则数组的连接运算符逻辑错误,未根据父节点运算符动态调整
- 未处理
not运算符,且多子节点的括号包裹逻辑缺失
修正后的递归方法
export function convertToRule(root: OperatoreLogico): string { // 将单个规则对象转换为格式化字符串 const formatRuleItem = (item: RegolaPerCollegamento): string => { const entries = Object.entries(item).map(([key, value]) => { // 字符串类型值加双引号,数字类型直接输出 const formattedValue = typeof value === 'string' ? `"${value}"` : value; return `${key}: ${formattedValue}`; }); return `{${entries.join(', ')}}`; }; // 递归处理节点,parentOp为当前节点所属的父运算符 const traverse = (node: OperatoreLogico, parentOp?: 'and' | 'or' | 'not'): string => { const parts: string[] = []; // 处理规则数组 if (node.regolaPerCollegamento) { const ruleItems = Array.isArray(node.regolaPerCollegamento) ? node.regolaPerCollegamento : [node.regolaPerCollegamento]; if (ruleItems.length > 0) { const connector = parentOp === 'and' ? ' && ' : parentOp === 'or' ? ' || ' : ''; const ruleStrings = ruleItems.map(formatRuleItem); parts.push(ruleStrings.length === 1 ? ruleStrings[0] : `(${ruleStrings.join(connector)})`); } } // 处理逻辑运算符节点 const operatorEntries = Object.entries(node).filter(([key]) => ['and', 'or', 'not'].includes(key)) as Array<['and' | 'or' | 'not', OperatoreLogico | OperatoreLogico[]]>; for (const [op, childNodes] of operatorEntries) { const children = Array.isArray(childNodes) ? childNodes : [childNodes]; const childResults = children.map(child => traverse(child, op)); let combined: string; if (op === 'not') { combined = childResults.map(res => `!${res}`).join(' '); } else { const connector = op === 'and' ? ' && ' : ' || '; combined = childResults.length === 1 ? childResults[0] : `(${childResults.join(connector)})`; } parts.push(combined); } // 拼接当前节点的所有子项结果 if (parts.length === 0) return ''; if (parts.length === 1) return parts[0]; const connector = parentOp === 'and' ? ' && ' : parentOp === 'or' ? ' || ' : ' && '; return `(${parts.join(connector)})`; }; // 处理根节点:识别根节点的外层运算符 const rootOps = Object.keys(root).filter(key => ['and', 'or', 'not'].includes(key)) as Array<'and' | 'or' | 'not'>; if (rootOps.length === 1) { const op = rootOps[0]; const childNodes = root[op]!; const children = Array.isArray(childNodes) ? childNodes : [childNodes]; const childResults = children.map(child => traverse(child, op)); const connector = op === 'and' ? ' && ' : op === 'or' ? ' || ' : ' '; return childResults.length === 1 ? childResults[0] : `(${childResults.join(connector)})`; } else { return traverse(root); } } // 测试示例 const json: OperatoreLogico = { "or": { "and": { "regolaPerCollegamento": [ { "tipoCollegamentoEsistente": 115, "quantita": "NESSUNO" }, { "tipoCollegamentoEsistente": 118, "quantita": "NESSUNO" } ] }, "or": { "regolaPerCollegamento": [ { "tipoCollegamento": 115, "minimo": 1 }, { "tipoCollegamento": 118, "minimo": 1 } ] } } }; console.log(convertToRule(json));
代码修正说明
分层递归逻辑:
- 新增
traverse内部函数专门处理递归,通过parentOp参数传递父节点运算符,明确子项的连接规则 - 根节点单独处理,先识别外层运算符再递归处理子节点
- 新增
结果收集与拼接:
- 用
parts数组收集当前节点的所有子项结果,避免原代码中返回值丢失的问题 - 递归调用的返回值被正确收集并参与后续拼接
- 用
规则格式化优化:
- 单独提取
formatRuleItem函数,统一处理规则对象到字符串的转换,自动区分字符串和数字类型的格式化方式
- 单独提取
运算符逻辑完善:
- 正确实现
and/or/not三种运算符的连接逻辑 - 支持单个或数组形式的子节点,兼容原代码的数组处理逻辑
- 自动为多子项添加括号,保证逻辑运算的优先级
- 正确实现
边界情况处理:
- 处理单个规则项的无括号场景
- 处理空规则数组的空字符串返回
- 处理根节点无外层运算符的直接遍历场景
内容的提问来源于stack exchange,提问作者travis_91
相关产品推荐
相关产品推荐

