在when内使用when / alternatives

时间:2019-05-22 07:25:05

标签: javascript typescript joi

我需要使用joi验证模式。

对象是这样的:

  1. 有一个名为“ type”的必需属性,其值可以为TYPE1TYPE2TYPE3
  2. 如果type === 'TYPE1',我们必须期望属性onetwothree处于同一级别。
  3. 如果type === 'TYPE2',我们必须期望属性fourfivesix处于同一级别。
  4. 如果为type === 'TYPE3',我们必须期望一个subtype属性处于同一级别,并可能具有值AB
    • 如果是subtype === 'A',那么我们必须期望属性seveneightnine处于同一级别。
    • 如果是subtype === 'B',那么我们必须期望属性teneleventwelve处于同一级别。

这是我想出的:

import { object, string, validate } from 'joi';

const obj1 = { // valid
  type: 'TYPE1',
  one: '01',
  two: '02',
  three: '03',
};
const obj2 = { // valid
  type: 'TYPE2',
  four: '04',
  five: '05',
  six: '06',
};
const obj3 = { // valid
  type: 'TYPE3',
  subtype: 'A',
  seven: '07',
  eight: '08',
  nine: '09',
};
const obj4 = { // valid
  type: 'TYPE3',
  subtype: 'B',
  ten: '10',
  eleven: '11',
  twelve: '12',
};

const joiSchema = object({
  // point 1
  type: string().valid('TYPE1', 'TYPE2', 'TYPE3').required(),
})
.when(
  // point 2
  object({ type: 'TYPE1' }).unknown(),
  {
    then: object({
      one: string().required(),
      two: string().required(),
      three: string().required(),
    }),
  },
)
.when(
  // point 3
  object({ type: 'TYPE2' }).unknown(),
  {
    then: object({
      four: string().required(),
      five: string().required(),
      six: string().required(),
    }),
  },
)
.when(
  // point 4
  object({ type: 'TYPE3' }).unknown(),
  {
    then: object(
      // if type === 'TYPE3', check for one of those schemas
      {
        // point 4
        subtype: string().valid('A', 'B'),
      },
    ).when(
      // point 4.1
      object({ subtype: 'A' }).unknown(),
      {
        then: object({
          seven: string().required(),
          eight: string().required(),
          nine: string().required(),
        }),
      },
    ).when(
      // point 4.2
      object({ subtype: 'B' }).unknown(),
      {
        then: object({
          ten: string().required(),
          eleven: string().required(),
          twelve: string().required(),
        }),
      },
    ),
  },
);

const result1 = validate(obj1, joiSchema);
console.log('Validating obj1')
if (result1.error) {
  console.error(result1.error.message);
}

const result2 = validate(obj2, joiSchema);
console.log('Validating obj2')
if (result2.error) {
  console.error(result2.error.message);
}

const result3 = validate(obj3, joiSchema);
console.log('Validating obj3')
if (result3.error) {
  console.error(result3.error.message);
}

const result4 = validate(obj4, joiSchema);
console.log('Validating obj4')
if (result4.error) {
  console.error(result4.error.message);
}

此代码段可在此处进行测试:https://repl.it/@AlessandroDe5/Joi-MCVE

它显示此错误:

AssertionError [ERR_ASSERTION]: Cannot merge type object with another type: alternatives
    at new AssertionError (internal/errors.js:315:11)
    at Object.exports.assert (/home/runner/node_modules/hoek/lib/index.js:559:11)
    at internals.Object.concat (/home/runner/node_modules/joi/lib/types/any/index.js:148:14)
    at internals.Alternatives.when (/home/runner/node_modules/joi/lib/types/alternatives/index.js:131:52)
    at index.ts:52:6
    at Script.runInThisContext (vm.js:65:33)
    at startRepl (/usr/local/lib/node_modules/ts-node-fm/src/bin.ts:157:12)
    at Object.<anonymous> (/usr/local/lib/node_modules/ts-node-fm/src/bin.ts:66:1)
    at Module._compile (internal/modules/cjs/loader.js:654:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)

如果我删除嵌套的when(第4、4.1、4.2点),它将正常工作并且当然会拒绝最后两个对象。

我还尝试将when替换为alternatives

.when(
  // point 4
  object({ type: 'TYPE3' }).unknown(),
  {
    then: alternatives().try(
      object({
        subtype: string().valid('A'),
        seven: string().required(),
        eight: string().required(),
        nine: string().required(),
      }),
    ).when(
      object({
        subtype: string().valid('B'),
        ten: string().required(),
        eleven: string().required(),
        twelve: string().required(),
      }),
    ),
  },
);

可以预料到我会得到完全相同的错误。

有办法以某种方式完成任务吗?

1 个答案:

答案 0 :(得分:0)

我建议使用 Joi.alternatives(),这是另一种方法,这样可以避免嵌套何时,因此您的架构应如下所示:

Joi.alternatives().try(
    Joi.object({
        type: Joi.string().valid('TYPE1').required(),
        one: Joi.string().required(),
        two: Joi.string().required(),
        three: Joi.string().required(),
    }),
    Joi.object({
        type: Joi.string().valid('TYPE2').required(),
        four: Joi.string().required(),
        five: Joi.string().required(),
        six: Joi.string().required(),
    }),
    Joi.object({
        type: Joi.string().valid('TYPE3').required(),
        subtype: Joi.string().valid('A', 'B')
    })
        .when(Joi.object({ subtype: 'A' }).unknown(), {
            then: Joi.object({
                seven: Joi.string().required(),
                eight: Joi.string().required(),
                nine: Joi.string().required(),
            }),
        })
        .when(Joi.object({ subtype: 'B' }).unknown(), {
            then: Joi.object({
                ten: Joi.string().required(),
                eleven: Joi.string().required(),
                twelve: Joi.string().required(),
            }),
        }),
);