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

Narrow type from array passed to mixed().oneOf() #1675

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

karlhorky
Copy link
Contributor

@karlhorky karlhorky commented May 27, 2022

@karlhorky
Copy link
Contributor Author

@jquense friendly bump, what do you think of the approach of this PR?

@karlhorky
Copy link
Contributor Author

@jquense closed #1230 just a couple of days ago: #1230 (comment)

So it's possible this has been implemented in 1.0.0-beta.5 or 1.0.0-beta.7

@jquense
Copy link
Owner

jquense commented Aug 22, 2022

Mixed still doesn't narrow, but string does. I'm not convinced that mixed should narrow, it may make the type too restrictive. Still need to think about it a bit

@karlhorky
Copy link
Contributor Author

karlhorky commented Aug 22, 2022

but string does

Is this new in 1.0.0-beta.5 or 1.0.0-beta.7? What does this look like in practice?


I'm not convinced that mixed should narrow

To me, it seems like usage of mixed().oneOf() should narrow in all cases. Especially if checking schemas against TS types.

For example, in what case would a user want something different than 'abc' | 'def' as the type of the following?

const mixed = yup.mixed().oneOf(['abc', 'def'] as const);

@karlhorky
Copy link
Contributor Author

karlhorky commented Aug 22, 2022

Regardless of whether it should narrow, mixed().oneOf() at least not return any as it currently does, see this sandbox for a demonstration of the broken behavior:

Screen Shot 2022-08-22 at 16 30 21

Screen Shot 2022-08-22 at 16 28 45

import { mixed } from "yup";

type IsAny<T> = unknown extends T ? (T extends {} ? T : never) : never;

type NotAny<T> = T extends IsAny<T> ? never : T;
function notAny<T>(x: NotAny<T>) {}

// Without using .oneOf() retains the type of MixedSchema<null, AnyObject, undefined, ''>
const schemaWorking = mixed<null>().defined();
notAny(schemaWorking); // ✅ This type is not `any`

// Using .oneOf() sets the type to `any`
const schemaBroken = mixed<null>().oneOf([null]).defined();
notAny(schemaBroken); // 💥 Type is `any`

@jquense
Copy link
Owner

jquense commented Aug 23, 2022

Is this new in 1.0.0-beta.5 or 1.0.0-beta.7? What does this look like in practice?

image

not new, its been in in most of the v1 releases

Regardless of whether it should narrow, mixed().oneOf() at least not return any as it currently does,

that is definately true, will fix

jquense added a commit that referenced this pull request Aug 23, 2022
@slashwhatever
Copy link

Update on this?

@karlhorky
Copy link
Contributor Author

karlhorky commented May 26, 2023

@jquense would you reconsider this PR?

Would be great to be able to represent this properly:

interface FormidableFile {
  hashAlgorithm: false | "sha1" | "md5" | "sha256";
}

const formidableFileSchema: ObjectSchema<FormidableFile> = object({ // 💥 Currently errors, see below
  hashAlgorithm: mixed()
    .oneOf([false, 'sha1', 'md5', 'sha256'] as const)
    .required(),
})

Currently this returns the following (confusing) error:

Type 'ObjectSchema<{ hashAlgorithm: AnyPresentValue; }, AnyObject, { hashAlgorithm: undefined; }, "">' is not assignable to type 'ObjectSchema<FormidableFile, AnyObject, any, "">'.
  The types of 'default(...).fields.hashAlgorithm' are incompatible between these types.
    Type 'Reference<unknown> | ISchema<AnyPresentValue, AnyObject, any, any>' is not assignable to type 'Reference<unknown> | ISchema<false | "sha1" | "md5" | "sha256", AnyObject, any, any>'.
      Type 'ISchema<AnyPresentValue, AnyObject, any, any>' is not assignable to type 'Reference<unknown> | ISchema<false | "sha1" | "md5" | "sha256", AnyObject, any, any>'.
        Type 'ISchema<AnyPresentValue, AnyObject, any, any>' is not assignable to type 'ISchema<false | "sha1" | "md5" | "sha256", AnyObject, any, any>'.
          Type 'AnyPresentValue' is not assignable to type 'false | "sha1" | "md5" | "sha256"'.

With the changes in this PR, the types match.

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.

TypeScript types: oneOf() should narrow/constrain the type
3 participants