Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: stricter when types and API #1542

Merged
merged 2 commits into from
Dec 28, 2021
Merged

feat: stricter when types and API #1542

merged 2 commits into from
Dec 28, 2021

Conversation

jquense
Copy link
Owner

@jquense jquense commented Dec 28, 2021

BREAKING CHANGE: The function version of when() has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. this is no longer set to the schema instance. and all functions must return a schema to be type safe

 string()
-   .when('other', function (other) => {
-      if (other) return this.required()
+   .when('other', ([other], schema) => {
+     return other ? schema.required() : schema
  })

@jquense jquense changed the base branch from master to next December 28, 2021 19:49
@jquense jquense merged commit da74254 into next Dec 28, 2021
@jquense jquense deleted the conditions branch December 28, 2021 20:12
jquense added a commit that referenced this pull request Jan 3, 2022
* feat: stricter `when` types and API (#1542)

BREAKING CHANGE: The function version of `when()` has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. `this` is no longer set to the schema instance.  and all functions _must_ return a schema to be type safe

```diff
 string()
-   .when('other', function (other) => {
-      if (other) return this.required()
+   .when('other', ([other], schema) => {
+     return other ? schema.required() : schema
  })
```

* feat: concat() is shallow and does not merge (#1541)

BREAKING CHANGE: concat works shallowly now. Previously concat functioned like a deep merge for object, which produced confusing behavior with incompatible concat'ed schema. Now concat for objects works similar to how it works for other types, the provided schema is applied on top of the existing schema, producing a new schema that is the same as calling each builder method in order

* docs: update readme

* chore: update to readonly arrays and test string type narrowing

* test: add boolean tests

* docs: more docs

* feat: allow mixed schema to specify type check

* feat: simplify base class hierarchy (#1543)

BREAKING CHANGE: `mixed` schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes. 

In general this should not affect anything unless you are extending (via `addMethod` or otherwise) `mixed` prototype. 

```diff
import {
-  mixed,
+  Schema,
} from 'yup';

- addMethod(mixed, 'method', impl)
+ addMethod(Schema, 'method', impl)
```

* chore: prep work for toggling coercion

* Publish v1.0.0-alpha.4

* chore: docs

* feat!: add json() method and remove default object/array coercion

BREAKING CHANGE: object and array schema no longer parse JSON strings by default, nor do they return `null` for invalid casts.

```ts
object().json().cast('{}')
array().json().cast('[]')
```
to mimic the previous behavior

* feat: Make Array generic consistent with others

BREAKING CHANGE: types only, `ArraySchema`  initial generic is the array type not the type of the array element. `array<T>()` is still the inner type.

* Publish v1.0.0-beta.0

* docs

* chore: improve internal test run APIs and Error handling (#1545)

* docs

* WIP

* chore: clean up internal test running APIs

* fix order

* feat: flat bundles and size reductions

Use rollup to produce flat bundles of yup.

* Publish v1.0.0-beta.1

* docs: pre release note

Co-authored-by: Michael Li <[email protected]>
@fini
Copy link

fini commented Feb 10, 2023

I just had to change all my 'when' rules to use function version, since I got a 'branch is not a function error'.

Error in function Condition.eval [as fn] in ./node_modules/yup/index.esm.js:175
branch is not a function

./node_modules/yup/index.esm.js:175

From:

    [prevEmployerName]: yup
      .string()
      .when([employmentStartYearName, employmentStartMonthName], {
        is: (empStartYear, empStartMonth) =>
          isEmploymentRecent(empStartYear, empStartMonth),
        then: yup.string().label(prevEmployerLabel).required(),
      }),

To:

    [prevEmployerName]: yup
      .string()
      .when([employmentStartYearName, employmentStartMonthName], {
        is: (empStartYear, empStartMonth) =>
          isEmploymentRecent(empStartYear, empStartMonth),
        then: (s) => s.label(prevEmployerLabel).required(),
      }),

This seems to have solved my branch is not a function error, and solved validation.
Note: I am using the yupResolver from react-hook-form, so it might be related to that as well, however the error occurs directly in the yup module.

@kavin-happyfox
Copy link

@fini the reason is due to this change

@gajus
Copy link

gajus commented Mar 6, 2023

export const phoneNumberAndServicesValidationSchema = object().shape({
  interestedInMatchmakerService: boolean().required('Please select an option.'),
  phoneNumber: string()
    .when('interestedInMatchmakerService', {
      is: true,
      then: string().required('Please enter your phone number.'),
    })
    .when('interestedInMatchmakerService', {
      is: false,
      then: string().nullable(),
    }),
});

How is this supposed to be refactored?

I think it now becomes:

export const phoneNumberAndServicesValidationSchema = object().shape({
  interestedInMatchmakerService: boolean().required('Please select an option.'),
  phoneNumber: string()
    .when('interestedInMatchmakerService', {
      is: true,
      then: (schema) => schema.required('Please enter your phone number.'),
    })
    .when('interestedInMatchmakerService', {
      is: false,
      then: (schema) => schema.nullable(),
    }),
});

@carlosrsabreu
Copy link

How we should refactor this?

  const schema = object({
    resalable: boolean().defined(),
    royaltyPayments: object().when('resalable', {
      is: true,
      then: object({
        enabled: boolean().required(),
        rate: number().when('enabled', {
          is: true,
          then: number().required(),
        }),
      }),
    }),
  })

@carlosrsabreu
Copy link

Would anyone be able to help us with this question? Thank you in advance!

How we should refactor this?

  const schema = object({
    resalable: boolean().defined(),
    royaltyPayments: object().when('resalable', {
      is: true,
      then: object({
        enabled: boolean().required(),
        rate: number().when('enabled', {
          is: true,
          then: number().required(),
        }),
      }),
    }),
  })

@jquense
Copy link
Owner Author

jquense commented Apr 20, 2023

Read through the docs. It demonstrates the correct syntax. Adjust yours to match

@anguiano
Copy link

anguiano commented May 19, 2023

@carlosrsabreu in theory

  const schema = object({
    resalable: boolean().defined(),
    royaltyPayments: object().when('resalable', {
      is: true,
      then: (schema) => schema({
          enabled: boolean().required(),
          rate: number().when('enabled', {
            is: true,
            then: (schema) => schema.required(),
          }),
       }),
      }),
    }),
  })

@DanielRuf
Copy link

DanielRuf commented Sep 28, 2023

Hm, how do we have to change this?

    then: yup.object().shape({
      field_3: yup.string().required(content.errors.required),
    }),
    otherwise: yup.object().shape({
      field_1: yup.string().required(content.errors.required),
      field_2: yup.mixed().when('regulation', {
        is: regulated,
        then: yup.string().required(content.errors.required),
      }),
    }),
    then: yup
      .number()
      .min(0, dimensions.height.errors.atDefault)
      .max(25, dimensions.height.errors.atDefault)
      .required(content.errors.required),
    otherwise: yup
      .number()
      .min(0, dimensions.height.errors.main)
      .max(25, dimensions.height.errors.main)
      .required(content.errors.required),

Especially then: yup.object().shape({. Is this now then: (schema) => schema.object().shape({ or then: (schema) => schema.shape({?

And yup.number(). becomes now (schema) => schema.? I do not yet understand why these calls like .number() have to be removed.

@anguiano
Copy link

anguiano commented Oct 13, 2023

Hm, how do we have to change this?

    then: yup.object().shape({
      field_3: yup.string().required(content.errors.required),
    }),
    otherwise: yup.object().shape({
      field_1: yup.string().required(content.errors.required),
      field_2: yup.mixed().when('regulation', {
        is: regulated,
        then: yup.string().required(content.errors.required),
      }),
    }),
    then: yup
      .number()
      .min(0, dimensions.height.errors.atDefault)
      .max(25, dimensions.height.errors.atDefault)
      .required(content.errors.required),
    otherwise: yup
      .number()
      .min(0, dimensions.height.errors.main)
      .max(25, dimensions.height.errors.main)
      .required(content.errors.required),

Especially then: yup.object().shape({. Is this now then: (schema) => schema.object().shape({ or then: (schema) => schema.shape({?

And yup.number(). becomes now (schema) => schema.? I do not yet understand why these calls like .number() have to be removed.

@DanielRuf Because you must return a schema to be type-safe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants