英文:
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.
<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}
                />
My Schema is...
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),
          }),
        }),
    }),
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 (<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)
If I remove the conditional validation all works...
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),
        }),
    }),
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("riskClassification", {
          is: (riskClassification) =>
            ["Medium", "High"].includes(riskClassification),
          then: () => yup.object({
            investigationType: yup
              .array()
              .label("Type of Investigation")
              .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("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")
    })
答案3
得分: 2
以下是翻译好的部分:
旧版本(0.3):条件验证的is、then和otherwise函数接受对象作为参数。
新版本(1):then和otherwise函数必须返回修改后的模式。它们现在采用空箭头函数() => ... 来返回修改后的模式。
旧版本(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 'yup';
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('attestationType', {
      is: (attestationType: optionsType) =>
        attestationType.label !== 'Standard',
      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(['helmetType', 'otherEquipement'], {
      is: (helmetType: optionsType[], otherEquipement: string) =>
        !helmetType?.length && !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(['shoesType', 'otherEquipement'], {
      is: (shoesType: optionsType[], otherEquipement: string) =>
        !shoesType?.length && !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(['shoesType', 'helmetType'], {
        is: (shoesType: optionsType[], helmetType: optionsType[]) =>
          !shoesType?.length && !helmetType?.length,
        then: Yup.string().min(4).required()
      }),
    isCefri: Yup.boolean().oneOf([true, false]),
    dosimeterType: Yup.object({}).when('isCefri', {
      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('isCefri', {
      is: true,
      then: Yup.string().min(7).max(7).required(),
      otherwise: Yup.string()
    })
  },
  [
    ['shoesType', 'helmetType'],
    ['shoesType', 'otherEquipement'],
    ['helmetType', 'otherEquipement']
  ]
);
export default formEpischema;
Here is now :
import * as Yup from 'yup';
interface optionsType {
  id: string;
  label: string;
  value: string;
}
const formEpischema = Yup.object().shape({
  attestationType: Yup.object({ // change is here 👈
    id: Yup.string().required(),
    label: Yup.string().required(),
    value: Yup.string().required()
  }),
  activityType: Yup.object().when('attestationType', {
    is: (attestationType: optionsType) => attestationType.label !== 'Standard',
    then: () => // change is here 👈
      Yup.object({
        id: Yup.string().required(),
        label: Yup.string().required(),
        value: Yup.string().required()
      }),
    otherwise: () => // change is here 👈
      Yup.object({
        id: Yup.string(),
        label: Yup.string(),
        value: Yup.string()
      })
  }),
  shoesType: Yup.array().when(['helmetType', 'otherEquipement'], {
    is: (helmetType: optionsType[], otherEquipement: string) => !helmetType?.length && !otherEquipement,
    then: () => // change is here 👈
      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(['shoesType', 'otherEquipement'], {
    is: (shoesType: optionsType[], otherEquipement: string) => !shoesType?.length && !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(['shoesType', 'helmetType'], {
    is: (shoesType: optionsType[], helmetType: optionsType[]) => !shoesType?.length && !helmetType?.length,
    then: () => Yup.string().min(4).required()
  }),
  isCefri: Yup.boolean().oneOf([true, false]),
  dosimeterType: Yup.object().when('isCefri', {
    is: true,
    then: () =>
      Yup.object({
        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('isCefri', {
    is: true,
    then: (schema) => schema.min(7).max(7).required(),
    otherwise: () => Yup.string()
  })
    },
  [
    ['shoesType', 'helmetType'],
    ['shoesType', 'otherEquipement'],
    ['helmetType', 'otherEquipement']
  ]
);
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('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
答案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("logCourtesyCall", {
is: (value) => value === false,
then: Yup.string().required("Field is required").max(250, "Maximum character limit exceed"),
otherwise: Yup.string().max(250, "Maximum character limit exceed"),
}),
accountManager: Yup.string().when("logCourtesyCall", {
is: (value) => value === false,
then: Yup.string().required("Field is required").max(50, "Maximum character limit exceed"),
otherwise: Yup.string().max(50, "Maximum character limit exceed"),
}),
});
// 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('emailStatus', {
is: false,
then: () =>
Yup.string().email('Invalid email address').required('Please enter email address'),
}),
otp: Yup.string().when('emailStatus', {
is: true,
then: () => Yup.string().min(6).max(6).required('Please enter OTP'),
}),
newPassword: Yup.string().when('otpStatus', {
is: true,
then: () =>
Yup.string()
.required('New password is required')
.min(8, 'Password must be at least 8 characters long')
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/,
'Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character',
),
}),
confirmPassword: Yup.string().when('otpStatus', {
is: true,
then: () =>
Yup.string().oneOf([Yup.ref('newPassword')], 'Both password need to be the same'),
}),
});
Hope this will help you. ![]()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论