检查 JSON 对象是否符合预期模式的最轻量级方法是什么?

What is the most lightweight way to check that a JSON object conforms to an expected schema?

这似乎是一个常见的乏味模式:

function handleResponse(httpResponseBody) {
  const body = JSON.parse(httpResponseBody);
  if (body.someField &&
      body.someField.length >= 5 &&
      body.someField[4].otherField &&
      body.someField[4].otherField.finalField) {
    /* ... do something with finalField ... */
  }
}

有点做作,但重点是如何避免像这样的样板验证逻辑而不求助于对主体的完整 JSON 模式验证,如果你只是想通过手术访问对象的某些部分并想要最低限度地验证该部分的结构是否符合预期?轻量级的东西,概念上很简单:

function handleResponse(httpResponseBody) {
  const body = JSON.parse(httpResponseBody);
  if (validate(body, '{ someField[>=5].otherField.finalField }') {
    /* ... safe to access body.someField[4].otherField.finalField directly ... */
  }
}

或者可能:

function handleResponse(httpResponseBody) {
  const body = JSON.parse(httpResponseBody);
  const finalField = access(body, '{ someField[4].otherField.finalField }');
  if (finalField) {
    /* ... */
  }
}

最简单的方法是将其简单地包装在 try/catch 块中:

var data = {body: { someField: [0,0,0,0, { otherField: { finalField: 'test'}}]}};
try {
   var finalField = data.body.someField[4].otherField.finalField;
   console.log(finalField);
} catch(e) {
   console.error('Invalid');
}

try {
   var finalField = data.body.someField[7].otherField.finalField;
   console.log(finalField);
} catch(e) {
   console.error('Invalid');
}

您还可以在 try/catch 块中再次使用 ES6 destructuring

try {
  var { body: { someField: [,,,,{ otherField: { finalField }}] }} = {body: { someField: [0,0,0,0, { otherField: { finalField: 'test'}}]}};

  console.log(finalField);
} catch(e) {
  console.error('Invalid');
}

try {
  var { body: { someField: [,,,,{ otherField: { finalField }}] }} = {body: { someField: [0,0,0, { otherField: { finalField: 'test'}}]}};
  console.log(finalField);
} catch (e) {
  console.error('Invalid');
}

如果你想使用点路径(例如 "body.someField.4.otherField.finalField" 你可以这样做:

var data = {body: { someField: [0,0,0,0, { otherField: { finalField: 'test'}}]}};
var finalField = 'body.someField.4.otherField.finalField'.split('.').reduce((o,i)=>o[i], data);
console.log(finalField);
try {
finalField = 'body.someField.7.otherField.finalField'.split('.').reduce((o,i)=> o[i], data);
console.log(finalField);
} catch(e) {
    console.error('Invalid');
}

我不知道你的设计是什么,但如果这是对象的预期格式,只需将你的逻辑放在 try catch 块中即可。

为子孙后代作答。基于 https://github.com/tc39/proposal-optional-chaining,在当前的 TypeScript 中可用,并作为 Babel 插件。

您可以使用可选链接。

const finalField = body.someField?.[4]?.otherField?.finalField;

if (finalField) {
    /* ... do something with finalField ... */
}