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

nonNullable to disallow null #3141

Closed
wants to merge 2 commits into from
Closed

Conversation

sezanzeb
Copy link

@sezanzeb sezanzeb commented Jan 15, 2024

z.any().nonNullable()
z.nonNullable(z.any())

can both be now used to make this throw:

z.any().nonNullable().parse(null)

This is not equivalent to unwrap (as proposed in #2190). Instead, this is equivalent to typescripts NonNullable type https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype

Copy link

netlify bot commented Jan 15, 2024

Deploy Preview for guileless-rolypoly-866f8a ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit a54ef93
🔍 Latest deploy log https://app.netlify.com/sites/guileless-rolypoly-866f8a/deploys/660c24129f466b00089a9566
😎 Deploy Preview https://deploy-preview-3141--guileless-rolypoly-866f8a.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@colinhacks
Copy link
Owner

colinhacks commented Mar 22, 2024

I appreciate the PR, but this is a little too niche to go into Zod core. This is better implemented with a transform.

const A = z.string().nullable().transform((val, ctx) => {
  if(val === null) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Cannot be null",
      path: [],
    })
    return z.NEVER;
  }
  return val;
})

type A = z.infer<typeof A>;
// string

@colinhacks colinhacks closed this Mar 22, 2024
@sezanzeb
Copy link
Author

I obviuosly disagree, otherwise I wouldn't have made the PR. It would have come handy at work when I decided to work on this.

Furthermore it is compliant with typescripts NonNullable, and not a funky Idea that I just made up. So if NonNullable would ever be a thing, it would be in the way this PR proposes.

The typescript developers didn't think a NonNullable type is too niche to add it to typescript.

Transformers are flexible, but they are not nearly as readable and beautiful like the zods other features.

And also, this addition already has automated tests and is fully documented. This is a finished feature that doesn't add immediate development overhead for you. It's as good as it gets.

@sezanzeb
Copy link
Author

sezanzeb commented Mar 22, 2024

I think zod should be made as similar to typescripts types as possible. I want to be able to replace all interfaces and such with zod types with beautiful zod structures. Therefore, I think as many of typescripts built ins (like NonNullable) should be replicated in zod.

Well, my 2 cents.

@colinhacks colinhacks reopened this Mar 23, 2024
@sezanzeb
Copy link
Author

I guess I should also add that I didn't encounter a situation in which I wanted to use this since making the PR, maybe someone else should comment on this instead. I can't give you a realistic estimate on how commonly this feature would be used. On the other hand, there are tons of other existing zod features that I didn't consider using since then as well, so...

@michaelhays
Copy link

What's more is the transform workaround here doesn't seem to work for me with z.any(), as nestedValue is still optional:

const schema = z.object({
  nestedValue: z
    .any()
    .nullable()
    .transform((val) => (val == null ? z.NEVER : val)),
})

type SchemaType = z.infer<typeof schema>
type SchemaType = {
  nestedValue?: any;
}

@sezanzeb
Copy link
Author

sezanzeb commented Apr 2, 2024

nonNullable also restricts undefined (https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype)

It's as good as it gets.

That aged well

committed the change.


use case: A gateway passes along all payloads it gets, and it doesn't care for their content, but it does check if the payloads are set by using z.unknown().nonNullable()

@colinhacks
Copy link
Owner

colinhacks commented Apr 4, 2024

nonNullable also restricts undefined

The fact that .nonNullable() would not be the inverse of .nullable() is a big footgun. But adding a .notNullable() method that disagrees with the NonNullable built-in is also a footgun. Two bad options, imo, so it's not likely I take any action here I'm afraid.

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.

None yet

3 participants