Definitelytyped: [@types/yup] Issues with predicate type after upgrading to latest 0.29.3

Created on 30 Sep 2020  路  5Comments  路  Source: DefinitelyTyped/DefinitelyTyped

  • [x] I tried using the @types/xxxx package and had problems.
  • [x] I tried using the latest stable version of tsc. https://www.npmjs.com/package/typescript
  • [ ] I have a question that is inappropriate for StackOverflow. (Please ask any appropriate questions there).
  • [x] [Mention](https://github.com/blog/821-mention-somebody-they-re-notified) the authors (see Definitions by: in index.d.ts) so they can respond.

    • Authors: Tagging @ejose19 and @iansan5653 for their input based on git blame. Also tagging library author @jquense

How should I resolve issue with providing correct predicate type

  • Below is the example code which throws type errors after upgrading yup to 0.29.3 and @types/yup to 0.29.7
        code: Yup.string()
          .required('Code is required.')
          .test('duplicate-record', 'Code must be unique.', function (this: Yup.TestContext, code: string) {
            for (const [i, r] of allocationTable.records.entries()) {
              if (code === r.code && `records[${i}].code` !== this.path) {
                return false;
              }
            }
            return true;
          }),

In this above example it looks if the code that user entered already exists in records entry and returns true if its unique else false if it already exists.

Here I'm checking if code is unique or not and returning boolean and I'm not checking if the code is string which apparently resolves the issue and I'm not sure if this is the right usage.

Type error that I get for above function is:

Argument of type '(this: TestContext<object>, code: string) => boolean' is not assignable to parameter of type 'AssertingTestFunction<any, object>'.
  Signature '(this: TestContext<object>, code: string): boolean' must be a type predicate.ts(2345)

AssertingTestFunction declaration looks like below in Yup Typings:

export type AssertingTestFunction<T, C> = (this: TestContext<C>, value: any) => value is T;

Another example code is:

    customerKey: Yup.object<CustomerKey>()
      .nullable(true)
      .shape({
        customerId: Yup.number(),
        customerCode: Yup.string().test('customerCodeTest', 'Customer is required', (value) => {
          return (
            formProps.eventType === TypeA ||
            (formProps.eventType === TypeB && value) // <------ Only required if eventType B is picked 
          );
        }),
      }),

For this code test I'm checking and returning value (truthy or falsy) only if TypeB is picked else returning true. Again I'm not checking if the value is string rather existence of the value itself for a certain eventType (separate field) selection.

Here's typing error for above code:

Argument of type '(this: TestContext<object>, value: string | null | undefined) => string | boolean | null | undefined' is not assignable to parameter of type 'AssertingTestFunction<any, object>'.
  Signature '(this: TestContext<object>, value: string | null | undefined): string | boolean | null | undefined' must be a type predicate.ts(2345)

Most helpful comment

@Imballinst That context as second argument is new but typescript definitions aren't updated yet. So you should use
function (value) { } instead and refer to context using this (or if you don't need the context, just use the arrow function but don't mention 2nd argument).

All 5 comments

For first issue, you're assigning code: string which is incorrect, just leave it as "code" (remember in tests, all properties can also be null | undefined.

function (this: Yup.TestContext, code) // Typescript will type code as string | null | undefined

For second issue, you need to use Boolean(value) or !!value or else the function will return string | boolean | null | undefined which is not the expected return value

return (
            formProps.eventType === TypeA ||
            (formProps.eventType === TypeB && !!value) // <------ Only required if eventType B is picked 
          );

@ejose19 Thank you for quick response, this resolves my issue. It seems that you have to force a boolean return value instead of relying on truthy/falsy value (which was prior allowed). Closing this issue.

hi @ejose19, sorry for bumping this. I stumbled on the same issue. I followed the actual documentation here: https://github.com/jquense/yup#mixedtestname-string-message-string--function-test-function-schema.

let jimmySchema = string().test(
  'is-jimmy',
  '${path} is not Jimmy',
  (value, context) => value === 'jimmy',
);

Not sure where I do it wrong, but I can't get away from the TypeErrors despite using your solution above. Could you guide me through it from this Sandbox link? https://codesandbox.io/s/peaceful-colden-p29u6?file=/src/index.ts. Thanks!

@Imballinst That context as second argument is new but typescript definitions aren't updated yet. So you should use
function (value) { } instead and refer to context using this (or if you don't need the context, just use the arrow function but don't mention 2nd argument).

Got it, @ejose19. Thank you for your explanation!

Was this page helpful?
0 / 5 - 0 ratings