YUP条件验证为什么会导致”branch is not a function”错误?

huangapple go评论72阅读模式
英文:

Why is YUP conditional validation causing branch is not a function at Condition.fn error

问题

我有一个 MUIRadioGroup(选项为 Low、Medium 和 High)和一个多选的 MUIAutocomplete 组件在我的表单上。

<MUIRadioGroup
  name="requestDetail.riskAssesmentDetail.riskClassification"
  label="Risk Classification"
  variant="outlined"
  size="small"
  defaultValue
/>

<MUIAutocomplete
  name="requestDetail.riskAssesmentDetail.safetyDetail.investigationType"
  label="Type of Investigation"
  variant="outlined"
  size="small"
  multiple
  disableCloseOnSelect
  options={API_Safety_InvestigationType}
/>

我的模式是...

requestDetail: yup.object().shape({
  riskAssesmentDetail: yup.object().shape({
    riskClassification: yup
      .string()
      .label("Risk Classification")
      .required()
      .typeError("Invalid Selection"),
    safetyDetail: yup
      .object()
      .shape()
      .when("riskClassification", {
        is: (riskClassification) =>
          ["Medium", "High"].includes(riskClassification),
        then: yup.object({
          investigationType: yup
            .array()
            .label("Type of Investigation")
            .min(1),
        }),
      }),
  }),

当单选按钮为 "Medium" 或 "High" 时,我需要对 MUIAutocomplete 组件执行验证。

我收到一个错误...

Uncaught (in promise) TypeError: branch is not a function
    at Condition.fn (index.esm.js:175:1)
    at Condition.resolve (index.esm.js:188:1)
    at index.esm.js:586:1
    at Array.reduce (<anonymous>)
    at ObjectSchema.resolve (index.esm.js:586:1)
    at ObjectSchema._cast (index.esm.js:1670:1)
    at ObjectSchema.cast (index.esm.js:610:1)
    at ObjectSchema._cast (index.esm.js:1683:1)
    at ObjectSchema.cast (index.esm.js:610:1)
    at ObjectSchema._cast (index.esm.js:1683:1)

如果我移除条件验证,一切都正常工作...

requestDetail: yup.object().shape({
  riskAssesmentDetail: yup.object().shape({
    riskClassification: yup.string().label("Risk Classification").required(),
    safetyDetail: yup
      .object()
      .shape({
        investigationType: yup.array().label("Type of Investigation").min(1),
      }),
  }),

这个错误是关于什么的,如何修复它?

英文:

I have a MUIRadioGroup (options = Low, Medium and High) and a multi-select MUIAutocomplete component on my form.

&lt;MUIRadioGroup
              name=&quot;requestDetail.riskAssesmentDetail.riskClassification&quot;
              label=&quot;Risk Classification&quot;
              variant=&quot;outlined&quot;
              size=&quot;small&quot;
              defaultValue
            /&gt;

&lt;MUIAutocomplete
                  name=&quot;requestDetail.riskAssesmentDetail.safetyDetail.investigationType&quot;
                  label=&quot;Type of Investigation&quot;
                  variant=&quot;outlined&quot;
                  size=&quot;small&quot;
                  multiple
                  disableCloseOnSelect
                  options={API_Safety_InvestigationType}
                /&gt;

My Schema is...

requestDetail: yup.object().shape({ ...
    riskAssesmentDetail: yup.object().shape({
      riskClassification: yup
        .string()
        .label(&quot;Risk Classification&quot;)
        .required()
        .typeError(&quot;Invalid Selection&quot;),
      safetyDetail: yup
        .object()
        .shape()
        .when(&quot;riskClassification&quot;, {
          is: (riskClassification) =&gt;
            [&quot;Medium&quot;, &quot;High&quot;].includes(riskClassification),
          then: yup.object({
            investigationType: yup
              .array()
              .label(&quot;Type of Investigation&quot;)
              .min(1),
          }),
        }),
    }),

When radio button is "Medium" or "High, I need to perform validation on the MUIAutocomplete component.

I get an error...

Uncaught (in promise) TypeError: branch is not a function
    at Condition.fn (index.esm.js:175:1)
    at Condition.resolve (index.esm.js:188:1)
    at index.esm.js:586:1
    at Array.reduce (&lt;anonymous&gt;)
    at ObjectSchema.resolve (index.esm.js:586:1)
    at ObjectSchema._cast (index.esm.js:1670:1)
    at ObjectSchema.cast (index.esm.js:610:1)
    at ObjectSchema._cast (index.esm.js:1683:1)
    at ObjectSchema.cast (index.esm.js:610:1)
    at ObjectSchema._cast (index.esm.js:1683:1)

If I remove the conditional validation all works...

requestDetail: yup.object().shape({ ...

    riskAssesmentDetail: yup.object().shape({
      riskClassification: yup.string().label(&quot;Risk Classification&quot;).required(),
      safetyDetail: yup
        .object()
        .shape({
          investigationType: yup.array().label(&quot;Type of Investigation&quot;).min(1),
        }),
    }),

What is this error about and how do I fix it?

答案1

得分: 28

我也遇到了这个问题。你的验证条件需要更改,以便在“then”属性上有一个函数。

  safetyDetail: yup
    .object()
    .shape()
    .when("riskClassification", {
      is: (riskClassification) =>
        ["Medium", "High"].includes(riskClassification),
      then: () => yup.object({
        investigationType: yup
          .array()
          .label("调查类型")
          .min(1),
      }),
    }),
英文:

I just ran into this issue as well. Your when validation needs to change to have a function on the then property.

      safetyDetail: yup
        .object()
        .shape()
        .when(&quot;riskClassification&quot;, {
          is: (riskClassification) =&gt;
            [&quot;Medium&quot;, &quot;High&quot;].includes(riskClassification),
          then: () =&gt; yup.object({
            investigationType: yup
              .array()
              .label(&quot;Type of Investigation&quot;)
              .min(1),
          }),
        }),

答案2

得分: 11

I ran into the same issue while doing upgrades. The old version of yup accepted the following.

someField: string().when("someOtherField", {
      is: true,
      then: string()
        .max(5, "Must be 5 characters or less")
        .required("Required")
    })

The above code was giving me a TypeScript error after upgrading yup. I solved it using the following

someField: string().when("someOtherField", {
      is: true,
      then: () => string()
        .max(5, "Must be 5 characters or less")
        .required("Required")
    })
英文:

I ran into the same issue while doing upgrades. The old version of yup accepted the following.

someField: string().when(&quot;someOtherField&quot;, {
      is: true,
      then: string()
        .max(5, &quot;Must be 5 characters or less&quot;)
        .required(&quot;Required&quot;)
    })

The above code was giving me a TypeScript error after upgrading yup. I solved it using the following

someField: string().when(&quot;someOtherField&quot;, {
      is: true,
      then: () =&gt; string()
        .max(5, &quot;Must be 5 characters or less&quot;)
        .required(&quot;Required&quot;)
    })

答案3

得分: 2

以下是翻译好的部分:

旧版本(0.3):条件验证的isthenotherwise函数接受对象作为参数。
新版本(1)thenotherwise函数必须返回修改后的模式。它们现在采用空箭头函数() => ... 来返回修改后的模式。

旧版本(0.3):直接在字段上调用验证方法,例如:Yup.string().required()。
新版本(1):验证方法必须通过模式来调用,例如:Yup.string().required() 变为 Yup.string().required()。

旧版本(0.3):使用mixed()方法在类型未指定时创建模式。
新版本(1):已移除mixed()方法。在创建模式时必须直接指定类型,例如:Yup.string()。

旧版本(0.3)validate()方法直接返回验证错误(如果存在),否则返回undefined。
新版本(1)validate()方法返回一个Promise。必须使用await或.then()来获取结果。

旧版本(0.3)isValid()方法直接返回true(如果验证成功),否则返回false。
新版本(1)isValid()方法返回一个Promise。必须使用await或.then()来获取结果。

旧版本(0.3):使用nullable()notRequired()方法来指定字段可以为null或不是必需的。
新版本(1):这些方法已被移除。要允许字段为null或不是必需的,可以在字段后面不调用任何验证方法(例如:Yup.string().nullable() 现在变成 Yup.string())。

新版本(1)oneOf()方法现在用于验证值是否属于给定的集合。例如:Yup.string().oneOf(['value1', 'value2']).

这些变化反映了Yup的两个版本之间的一些重要差异。

英文:

for those who want a real and complex example :
Here is before upgrade version :

import * as Yup from &#39;yup&#39;;

interface optionsType {
  id: string;
  label: string;
  value: string;
}

const formEpischema = Yup.object().shape(
  {
    attestationType: Yup.object({}).shape({
      id: Yup.string().required(),
      label: Yup.string().required(),
      value: Yup.string().required()
    }),
    activityType: Yup.object({}).when(&#39;attestationType&#39;, {
      is: (attestationType: optionsType) =&gt;
        attestationType.label !== &#39;Standard&#39;,
      then: Yup.object({}).shape({
        id: Yup.string().required(),
        label: Yup.string().required(),
        value: Yup.string().required()
      }),
      otherwise: Yup.object({
        id: Yup.string(),
        label: Yup.string(),
        value: Yup.string()
      })
    }),
    shoesType: Yup.array().when([&#39;helmetType&#39;, &#39;otherEquipement&#39;], {
      is: (helmetType: optionsType[], otherEquipement: string) =&gt;
        !helmetType?.length &amp;&amp; !otherEquipement,
      then: Yup.array()
        .of(
          Yup.object().shape({
            id: Yup.string().required(),
            label: Yup.string().required(),
            value: Yup.string().required()
          })
        )
        .min(1)
        .required()
    }),
    shoesCriteria: Yup.object({}).shape({
      id: Yup.string(),
      label: Yup.string(),
      value: Yup.string()
    }),
    shoesSize: Yup.number().min(10).max(55),
    helmetType: Yup.array().when([&#39;shoesType&#39;, &#39;otherEquipement&#39;], {
      is: (shoesType: optionsType[], otherEquipement: string) =&gt;
        !shoesType?.length &amp;&amp; !otherEquipement,
      then: Yup.array()
        .of(
          Yup.object().shape({
            id: Yup.string().required(),
            label: Yup.string().required(),
            value: Yup.string().required()
          })
        )
        .min(1)
        .required()
    }),
    otherEquipement: Yup.string()
      .min(4)
      .when([&#39;shoesType&#39;, &#39;helmetType&#39;], {
        is: (shoesType: optionsType[], helmetType: optionsType[]) =&gt;
          !shoesType?.length &amp;&amp; !helmetType?.length,
        then: Yup.string().min(4).required()
      }),
    isCefri: Yup.boolean().oneOf([true, false]),
    dosimeterType: Yup.object({}).when(&#39;isCefri&#39;, {
      is: true,
      then: Yup.object({}).shape({
        id: Yup.string().required(),
        label: Yup.string().required(),
        value: Yup.string().required()
      }),
      otherwise: Yup.object({
        id: Yup.string(),
        label: Yup.string(),
        value: Yup.string()
      })
    }),
    dosimeterRef: Yup.string().when(&#39;isCefri&#39;, {
      is: true,
      then: Yup.string().min(7).max(7).required(),
      otherwise: Yup.string()
    })
  },
  [
    [&#39;shoesType&#39;, &#39;helmetType&#39;],
    [&#39;shoesType&#39;, &#39;otherEquipement&#39;],
    [&#39;helmetType&#39;, &#39;otherEquipement&#39;]
  ]
);

export default formEpischema;


Here is now :

import * as Yup from &#39;yup&#39;;

interface optionsType {
  id: string;
  label: string;
  value: string;
}

const formEpischema = Yup.object().shape({
  attestationType: Yup.object({ // change is here &#128072;
    id: Yup.string().required(),
    label: Yup.string().required(),
    value: Yup.string().required()
  }),

  activityType: Yup.object().when(&#39;attestationType&#39;, {
    is: (attestationType: optionsType) =&gt; attestationType.label !== &#39;Standard&#39;,
    then: () =&gt; // change is here &#128072;
      Yup.object({
        id: Yup.string().required(),
        label: Yup.string().required(),
        value: Yup.string().required()
      }),
    otherwise: () =&gt; // change is here &#128072;
      Yup.object({
        id: Yup.string(),
        label: Yup.string(),
        value: Yup.string()
      })
  }),

  shoesType: Yup.array().when([&#39;helmetType&#39;, &#39;otherEquipement&#39;], {
    is: (helmetType: optionsType[], otherEquipement: string) =&gt; !helmetType?.length &amp;&amp; !otherEquipement,
    then: () =&gt; // change is here &#128072;
      Yup.array()
        .of(
          Yup.object().shape({
            id: Yup.string().required(),
            label: Yup.string().required(),
            value: Yup.string().required()
          })
        )
        .min(1)
        .required()
  }),

  shoesCriteria: Yup.object({
    id: Yup.string(),
    label: Yup.string(),
    value: Yup.string()
  }),

  shoesSize: Yup.number().min(10).max(55),

  helmetType: Yup.array().when([&#39;shoesType&#39;, &#39;otherEquipement&#39;], {
    is: (shoesType: optionsType[], otherEquipement: string) =&gt; !shoesType?.length &amp;&amp; !otherEquipement,
    then: () =&gt;
      Yup.array()
        .of(
          Yup.object().shape({
            id: Yup.string().required(),
            label: Yup.string().required(),
            value: Yup.string().required()
          })
        )
        .min(1)
        .required()
  }),

  otherEquipement: Yup.string().min(4).when([&#39;shoesType&#39;, &#39;helmetType&#39;], {
    is: (shoesType: optionsType[], helmetType: optionsType[]) =&gt; !shoesType?.length &amp;&amp; !helmetType?.length,
    then: () =&gt; Yup.string().min(4).required()
  }),

  isCefri: Yup.boolean().oneOf([true, false]),

  dosimeterType: Yup.object().when(&#39;isCefri&#39;, {
    is: true,
    then: () =&gt;
      Yup.object({
        id: Yup.string().required(),
        label: Yup.string().required(),
        value: Yup.string().required()
      }),
    otherwise: () =&gt;
      Yup.object({
        id: Yup.string(),
        label: Yup.string(),
        value: Yup.string()
      })
  }),

  dosimeterRef: Yup.string().when(&#39;isCefri&#39;, {
    is: true,
    then: (schema) =&gt; schema.min(7).max(7).required(),
    otherwise: () =&gt; Yup.string()
  })
    },
  [
    [&#39;shoesType&#39;, &#39;helmetType&#39;],
    [&#39;shoesType&#39;, &#39;otherEquipement&#39;],
    [&#39;helmetType&#39;, &#39;otherEquipement&#39;]
  ]
);

export default formEpischema;


Old version (0.3): The is, then, and otherwise functions of conditional validations accepted objects as arguments.
New version (1): The then and otherwise functions must return a modified schema. They now take empty arrow functions () => ... to return the modified schema.

Old version (0.3): Validation methods such as required(), min(), max(), etc. were called directly on the fields (for example: Yup.string().required()).
New version (1): Validation methods must be called via the schema (for example: Yup.string().required() becomes Yup.string().required()).

Old version (0.3): The mixed() method was used to create a schema when the type was not specified.
New version (1): The mixed() method has been removed. You must specify the type directly when creating the schema (for example: Yup.string()).

Old version (0.3): The validate() method directly returned validation errors if they existed, otherwise returned undefined.
New version (1): The validate() method returns a promise. You must use await or .then() to get the results.

Old version (0.3): The isValid() method directly returned true if the validation was successful, otherwise returned false.
New version (1): The isValid() method returns a promise. You must use await or .then() to get the results.

Old version (0.3): The nullable() and notRequired() methods were used to specify that a field could be null or not required.
New version (1): These methods have been removed. To allow a field to be null or not required, you can simply not call any validation method after the field (eg: Yup.string().nullable() just becomes Yup.string()).

New version (1): The oneOf() method is now used to validate that a value is part of a given set. For example: Yup.string().oneOf(['value1', 'value2']).
These changes reflect some of the important differences between the two versions of Yup.

答案4

得分: 0

When validation now has a new syntax:

let schema = object({
id: yup.number().notRequired(),
thumbnail: yup.mixed().when('id', {
is: (id: number | undefined) => id !== undefined,
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired(),
});

Notice the then: and otherwise: are functions with schema as a parameter.
More examples from the documentation

英文:

When validation now has a new syntax:

let schema = object({
id: yup.number().notRequired(),
thumbnail: yup.mixed().when(&#39;id&#39;, {
is: (id: number | undefined) =&gt; id !== undefined,
then: (schema) =&gt; schema.required(),
otherwise: (schema) =&gt; schema.notRequired(),
});

Notice the then: and otherwise: are functions with schema as a parameter.
More examples from the documentation

答案5

得分: 0

我也遇到了同样的问题在JavaScript中使用了Yup条件验证模式使用了`when`条件

像这样 // JAVASCRIPT VERSION

export const CreateTicketValidationSchema = Yup.object({

  // 为礼貌电话制作的额外验证
  logCourtesyCall: Yup.boolean(),
  customer: Yup.string().when("logCourtesyCall", {
    is: (value) => value === false,
    then: Yup.string().required("字段是必需的").max(250, "超出最大字符限制"),
    otherwise: Yup.string().max(250, "超出最大字符限制"),
  }),
  accountManager: Yup.string().when("logCourtesyCall", {
    is: (value) => value === false,
    then: Yup.string().required("字段是必需的").max(50, "超出最大字符限制"),
    otherwise: Yup.string().max(50, "超出最大字符限制"),
  }),
});

// 如果你在Yup的TypeScript版本中遇到问题,可以使用更新的代码

export const forgetPasswordValidation = Yup.object().shape({
  emailStatus: Yup.bool(),
  otpStatus: Yup.bool(),

  email: Yup.string().when('emailStatus', {
    is: false,
    then: () =>
      Yup.string().email('无效的电子邮件地址').required('请输入电子邮件地址'),
  }),

  otp: Yup.string().when('emailStatus', {
    is: true,
    then: () => Yup.string().min(6).max(6).required('请输入OTP'),
  }),

  newPassword: Yup.string().when('otpStatus', {
    is: true,
    then: () =>
      Yup.string()
        .required('需要新密码')
        .min(8, '密码必须至少为8个字符')
        .matches(
          /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/,
          '密码必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符',
        ),
  }),

  confirmPassword: Yup.string().when('otpStatus', {
    is: true,
    then: () =>
      Yup.string().oneOf([Yup.ref('newPassword')], '两个密码必须相同'),
  }),
});

希望这能帮到你 :)
英文:

I too was facing same problem where I used Yup conditional validation schema in Javascript with when condition,

Like this // JAVASCRIPT VERSION

    export const CreateTicketValidationSchema = Yup.object({
// Extra validation for courtesy call making
logCourtesyCall: Yup.boolean(),
customer: Yup.string().when(&quot;logCourtesyCall&quot;, {
is: (value) =&gt; value === false,
then: Yup.string().required(&quot;Field is required&quot;).max(250, &quot;Maximum character limit exceed&quot;),
otherwise: Yup.string().max(250, &quot;Maximum character limit exceed&quot;),
}),
accountManager: Yup.string().when(&quot;logCourtesyCall&quot;, {
is: (value) =&gt; value === false,
then: Yup.string().required(&quot;Field is required&quot;).max(50, &quot;Maximum character limit exceed&quot;),
otherwise: Yup.string().max(50, &quot;Maximum character limit exceed&quot;),
}),
});

// UPDATED CODE IF YOU ARE FACING ISSUE IN TYPESCRIPT VERSION OF YUP

  export const forgetPasswordValidation = Yup.object().shape({
emailStatus: Yup.bool(),
otpStatus: Yup.bool(),
email: Yup.string().when(&#39;emailStatus&#39;, {
is: false,
then: () =&gt;
Yup.string().email(&#39;Invalid email address&#39;).required(&#39;Please enter email address&#39;),
}),
otp: Yup.string().when(&#39;emailStatus&#39;, {
is: true,
then: () =&gt; Yup.string().min(6).max(6).required(&#39;Please enter OTP&#39;),
}),
newPassword: Yup.string().when(&#39;otpStatus&#39;, {
is: true,
then: () =&gt;
Yup.string()
.required(&#39;New password is required&#39;)
.min(8, &#39;Password must be at least 8 characters long&#39;)
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&amp;])[A-Za-z\d@$!%*?&amp;]+$/,
&#39;Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character&#39;,
),
}),
confirmPassword: Yup.string().when(&#39;otpStatus&#39;, {
is: true,
then: () =&gt;
Yup.string().oneOf([Yup.ref(&#39;newPassword&#39;)], &#39;Both password need to be the same&#39;),
}),
});

Hope this will help you. YUP条件验证为什么会导致”branch is not a function”错误?

huangapple
  • 本文由 发表于 2023年2月24日 15:38:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75553752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定