
本文介绍一种基于递归的 TypeScript 方法,为具有双向嵌套关系(QuestionModel ↔ ResponseModel)的 JSON 数据自动添加语义化、路径式的 id 字段,确保每个节点 ID 唯一且可追溯其层级路径。
本文介绍一种基于递归的 typescript 方法,为具有双向嵌套关系(questionmodel ↔ responsemodel)的 json 数据自动添加语义化、路径式的 `id` 字段,确保每个节点 id 唯一且可追溯其层级路径。
在构建动态问答系统、表单引擎或决策树配置时,常需为嵌套结构中的每个节点分配唯一标识符(id),以便前端绑定、状态追踪或后端校验。本例中,QuestionModel 与 ResponseModel 相互嵌套:一个问题(QuestionModel)包含多个响应选项(responses: ResponseModel[]),而每个响应又可关联下一级问题(questions: QuestionModel[])。这种双向递归结构要求 ID 必须按深度优先顺序生成,并体现完整祖先路径。
核心思路是递归遍历 + 路径累积:从根节点开始,每进入一层子节点,就将当前节点的 label(经规范化处理)追加到父级 id 后,用下划线 _ 连接。为此,我们定义统一处理函数 identify(),它能同时适配 QuestionModel 和 ResponseModel 类型:
type ResponseModel = {
label: string;
questions?: QuestionModel[];
id?: string;
};
type QuestionModel = {
label: string;
responses?: ResponseModel[];
id?: string;
};
const identify = (
data: QuestionModel | ResponseModel,
path = ''
): QuestionModel | ResponseModel => {
// 规范化 label:移除空格、标点等,仅保留字母数字(可按需扩展)
const safeLabel = data.label.replace(/[^a-zA-Z0-9]/g, '');
data.id = path ? `${path}_${safeLabel}` : safeLabel;
// 若存在 questions 数组,递归处理每个 QuestionModel
if ('questions' in data && Array.isArray(data.questions)) {
data.questions.forEach(q => identify(q, data.id));
}
// 若存在 responses 数组,递归处理每个 ResponseModel
if ('responses' in data && Array.isArray(data.responses)) {
data.responses.forEach(r => identify(r, data.id));
}
return data;
};
✅ 使用示例:
const input: QuestionModel = {
label: "your destination?",
responses: [
{
label: "USA",
questions: [
{
label: "do you have a visa?",
responses: [{ label: "yes" }, { label: "no" }]
}
]
},
{
label: "Canada",
questions: [
{
label: "do you have a work licence?",
responses: [{ label: "yes" }, { label: "no" }]
}
]
}
]
};
const result = identify(input);
console.log(JSON.stringify(result, null, 2));
// 输出即为符合预期的带完整层级 ID 的 JSON
⚠️ 注意事项:
-
label规范化逻辑(如replace(/[^a-zA-Z0-9]/g, ''))可根据业务需要调整,例如支持 Unicode 字母、保留连字符等; - 函数直接修改原对象。如需保持不可变性,应在递归前对
data进行浅拷贝(如{ ...data }),并对数组使用map()创建新引用; - 类型守卫
'questions' in data和'responses' in data确保了类型安全,TypeScript 可据此精确推导分支内的属性可用性; - 深度过大的嵌套可能引发栈溢出,生产环境建议增加递归深度限制或改用显式栈(stack-based)迭代实现。
通过该方案,你无需手动维护层级状态或编写多层 for 循环,即可稳健、清晰、类型安全地为任意深度的嵌套问答结构注入可读性强、路径明确的唯一 ID。











