Giter Club home page Giter Club logo

zod's Issues

Custom error messages

Is there a way to hook into the validation error messages to provide custom ones?

This would be useful for client-side validation when the errors are user-facing and might need to be translated.

Add comparison to runtypes

Hey @vriad, this package looks awesome. I am wondering (and I am sure other's who are reading the README) what the difference is between this package and runtypes.

Would be great to add this info to the README as well!

Generate class from object schema

Just like function implementation, it would be interesting to create an object implement(readonly: bool) method, that would create an anonymous class having the following functionality:

  • Has a constructor(t?: Type) that validates the object
  • Defines getters and setters (if not readonly)
  • May offer assign(other: Partial<Type>) or with(other: Partial<Type>), that respectively assign or copies the object and assign values, then runs validation

This would help creating ES6 classes inheriting from this base class, with validation built-in:

class MyUser extends userSchema.implement() {
    set password(pw: string) {
        this.passwordDigest = hash(pw);
    }
}

There are a few unknowns for this: specifically, in case of nested objects that have an implementation, it would be great to return an instance of that implementation rather than a bare object. Some mapping between ZodType and implementation could theoretically be passed to Implement.

Type guards vs Zod

Hi!

I am wondering what are the differences between Zod and typescript type guards. What are the pros/cons/limits/purposes for each.

ValidationError.path

When Zod throws a validation error, specify where in the schema that error occurred. Can be very helpful for large schemas.

Split off from #14.

Type assertions

I've been thinking a lot about validation libaries and I share your frustration with Yup. Yup does not get everything right. I'm scared about to introducing io-ts is it has a high a cognitive overhead, but I really love what io-ts does.

I think I'll experiment with this libarary a bit, but in terms of io-ts features do you think zod could be improve with these features?

  • built in type guards - i.e. io-ts's is() method on codecs.
  • built in type assertions - (maybe call it assert()) using the new assertion function types in typescript 3.7 (io-ts doesn't actually have this probably because it wants us to use Either instead of exceptions)
  • branded types - doing io-ts's symbol trickery to create types like NonZeroNumber or Email
    • it might be difficult to do that one while remaining ergonomic

Is published package not transpiled?

I'm developing a aws lambda based application, that means I cannot direcly use typescript code when deploying, when I tried to deploy a lambda using zod, my webpack process failed with the following error:

Error: TypeScript emitted no output for /Users/osp/dev/strestsaas/server/node_modules/zod/index.ts. By default, ts-loader will not compile .ts files in node_modules.
You should not need to recompile .ts files there, but if you really want to, use the allowTsInNodeModules option.

I think the published version of the package should not directly link to .ts files in order for transpiled projects to work, right?

Generating Zod schema from TS type definitions

Love this library! I'm just beginning to convert a large TS project with many types, and I'm wondering how feasible it would be to automatically run through a file and convert any TS types to a zod schema and the accompanying inferred type. Or perhaps using the language server somehow would be easier? Either way, it would remove a ton of tedium from adopting zod for an existing project.

I guess I'll just barrel through and convert them one by one, which will probably take me a few hours at least, but figured I'd suggest this for those who might end up in a similar spot.

discriminated union regression between 1.0.9 and 1.3.0

The following schema

export const CellResultsAPIValidator = z.union([
  z.object({
    kind: z.literal("error"),
    error: z.object({
      message: z.string(),
      type: z.string(),
    }),
  }),
  z.object({
    kind: z.literal("results"),
    results: z
      .array(
        z.union([
          z.object({
            kind: z.literal("data"),
            data: z.tuple([z.string(), z.string(), z.string()]),
          }),
          z.object({
            kind: z.literal("error"),
            error: z.tuple([z.string(), z.string(), z.object({})]),
          }),
          z.object({
            kind: z.literal("skipped"),
          }),
        ])
      )
      .nonempty(),
  }),
]);

no longer validates the following

{ Error: Type mismatch in union.
Received: {
  "kind": "results",
  "results": [
    {
      "kind": "error",
      "error": [
        "InvalidReferenceError",
        "object type or alias 'User' does not exist",
        {
          "65521": "7",
          "65522": "11",
          "65523": "1",
          "65524": "8"
        }
      ]
    }
  ]
}

Expected: object OR object
    at new ZodError (/Users/yury/dev/edge/tutorial/node_modules/zod/lib/src/ZodError.js:20:28)
    at Function.ZodError.create (/Users/yury/dev/edge/tutorial/node_modules/zod/lib/src/ZodError.js:66:21)
    at Function.ZodError.fromString (/Users/yury/dev/edge/tutorial/node_modules/zod/lib/src/ZodError.js:71:25)
    at ZodUnion.parse (/Users/yury/dev/edge/tutorial/node_modules/zod/lib/src/parser.js:159:39)

after upgrading from 1.0.9 to 1.3.0

Date type handling?

This lib looks like a really nice approach. I don't see support for Date types, though. Do you have a plan to support them?

Support for custom validation

Is there any plan to support custom validation?
It could be of the form: z.string().validate(someValidationFunction).

That would be a great help to build advanced schemas.

This could also take the form of custom types, but for now, z.ZodType / z.ZodTypeDef not being exposed as part of the API make it a hack IMO.

No unknown keys

This feature causes yup to throw an error on validation if there's a property on the object that doesn't match the schema. Similar to yup.object().noUnknown()

Split off from #14.

Partial Schema Validation

Hey man! Great job with the library! Coming from io-ts I really like how similar the syntax is. I'm looking for a feature that I have yet to find in any schema validation libraries. The ability to validate both complete and partial input against a single defined schema.

The use case is this. I have an API that allows creation and update of a resource. Both operations need to validate the input. In the creation case, the input needs to strictly adhere to the schema. In the update case, any partial input that matches a subset of the schema should be accepted.

I can accomplish this with any schema validation library by creating 2 schemas but my schemas are quite large and this would be painful. It would be great to be able to either:

  • Clone a schema as a "deep partial" in which every nested prop is converted to partial.
  • Parse/decode input using a "asPartial" option that allows some (or all) properties to be missing.

Thanks for contributing this library to the community!

A couple of yup features that would be nice to have

I'm really impressed with this project and its ease of use. There are a couple of features from yup that would be really useful.

#1. yup.object().noUnknown() - This feature causes yup to throw an error on validation if there's a property on the object that doesn't match the schema
#2. ValidationError.path - When yup throws a validation error, it specifies where in the schema that error occurred which can be very helpful for large schemas

Optional Properties was broken

It was worked in 1.0.9 , but broken in 1.2.3 .

export const stackProps = z
    .object({
        direction: Direction.optional(),
        horizontalAlign: Alignment.optional(),
        verticalAlign: Alignment.optional(),
        wrap: z.boolean().optional(),
        grow: z.boolean().optional(),
        shrink: z.boolean().optional(),
    })

type PropType = z.TypeOf<typeof stackProps>

image
image

Typo in the doc?

Hi!

Awesome work on this lib, I was waiting for years for someone to tackle this problem ;)

const dogsList = z.array(dogSchema);

dogsList.parse([
  { name: "Cujo", neutered: null },
  { name: "Fido", age: 4, neutered: true },
]) // passes

dogsList.parse([]) // passes

I believe this shouldn't pass because of the lack of age in the first item right?

Is it possible to add default values?

Hi, I love this library, it's perfect for the project I'm currently working on. I come from Joi, and it has a .default('value') for specifying a default value if not set. Does this library have something similar? is that a possibility?

Thanks

ZodObject methods (pick, omit, partial, etc.) for intersections and unions of objects

I've been converting lots of TS types to zod. It's going pretty smoothly. Again, thanks for the excellent work on this lib! But some of the types are fairly complex with nested intersections and unions of object types, and I find myself really wishing I could use the ZodObject methods on these types, especially pick, omit, and partial.

So for a zod definition like this:

const schema = z.intersection(
  z.object({key1: z.string()}), 
  z.union([
    z.object({key2: z.string()}),
    z.object({key3: z.string()}),
  ])
);

I'd love to be able to do:

schema.pick({key1: true, key3: true});
schema.omit({key2: true});
schema.partial();

And same for other structures: unions of objects, unions of intersections, etc.

It seems like it could be doable to call them recursively through all levels of nesting with the appropriate subset of keys as long as every intersection/union resolves to an object? Maybe type inference is an issue?

I'm getting around this by breaking up complex types into many constituent ZodObject schemas, and then re-composing them using the object methods as needed, but it would be a lot easier to just call the methods directly on the full schema.

Can't build in my project with strictPropertyInitialization: true

Because zod isn't compiled when it's distributed in npm, my TS compiler tries to compile it. However, my project has strict: true in its config options, with no strict flags turned off, and so it ends up failing to build because zod has strictPropertyInitialization set to false. I get a handful of errors like Property 'schema' has no initializer and is not definitely assigned in the constructor

I currently can only use this library in my app if my strict compile options are set to what zod has, which is definitely not preferable. (And that's a shame because I really like the idea of this and I too was this close to trying to write my own library after being unhappy with the status quo.)

I think it would help a lot if the project was actually pre-compiled, and the JS + .d.ts files were distributed in npm, instead of the raw TS files.

(Also, side note that is kind of related to my above suggestion: I run our app using ts-node, and I get Cannot use import statement outside a module when ts-node tries to import zod. I'm pretty sure that this would also be fixed by releasing the compiled code instead of the raw TS.)

Middle Ground between strict and unstrict

Often when calling an HTTP endpoint, we're only interested in small bits of the data, but not the whole response. I, therefore, tried to model a "zod" (don't know what you call it :) ) based on that shape. Of course, I got an error because of unexpected types. The docs pointed me to "nonstrict" mode, which works great. I have a guarantee that the properties I need are there. The only issue is that it's not typesafe...the "nonstrict" mode carries over to the other end, and I can ask for any property I want, even if it doesn't exist.

Is there a hybrid mode? Or perhaps a setting in parse that doesn't error when coming across unexpected properties.

Union errors don't point to actual problem

When trying to parse a union type you get a very generic error that doesn't tell you what actually went wrong.

import * as z from 'zod';

enum ContactType {
    Address = 'ADDRESS',
    Phone = 'PHONE',
}

const addressSchema = z.object({
    kind: z.literal(ContactType.Address),
    address: z.object({
        streetAddress: z.string(),
        city: z.string(),
        stateOrProvince: z.string(),
        zipCode: z.string(),
    }),
});

const phoneSchema = z.object({
    kind: z.literal(ContactType.Phone),
    phone: z.string(),
});

const contactSchema = z.union([ addressSchema, phoneSchema ]);

const data = {
    kind: ContactType.Address,
    address: {
        streetAddress: '123 Fake Street',
        city: 'Springfield',
        stateOrProvince: 'OH',
        // Missing zipCode
    },
};

contactSchema.parse(data);

This will give you:

Error parsing union.
Received: {
  "kind": "ADDRESS",
  "address": {
    "streetAddress": "123 Fake Street",
    "city": "Springfield",
    "stateOrProvince": "OH"
  }
}
Expected: object OR object

If you change the last line to addressSchema.parse(data); you get something useful:

`address.zipCode`: Non-string type: undefined

It would be nice if this worked more like TypeScript itself does when type checking unions and told you why each possible type in the union failed to work. Perhaps something like:

object: Unexpected key(s) in object: 'address'
object: `address.zipCode`: Non-string type: undefined

Even better would be if it could give something more useful than object for the names of these but I'm not sure how you'd accomplish that without adding some means of providing metadata for types.

Include src in compiled package

My webpack throwing a lot of warnings about sourcemaps.

WARNING in ./node_modules/zod/lib/types/string.js
Module Warning (from ./node_modules/source-map-loader/index.js):
(Emitted value instead of an instance of Error) Cannot find source file '../../src/types/string.ts': Error: Can't resolve '../../src/types/string.ts' in '/Users/okhomenko/brightback/brightback-server/src/main/webpack/node_modules/zod/lib/types'

WARNING in ./node_modules/zod/lib/types/object.js
Module Warning (from ./node_modules/source-map-loader/index.js):
(Emitted value instead of an instance of Error) Cannot find source file '../../src/types/object.ts': Error: Can't resolve '../../src/types/object.ts' in '/Users/okhomenko/brightback/brightback-server/src/main/webpack/node_modules/zod/lib/types'

It's trying to merge sourcemaps from zod and can't find source typescript files.
@vriad Could you please include src as part of the published package?

Basic Zod Example does not compile

I tried to use Zod and cannot get even the most basic example from the documentation to compile.

Here is the code:

import zod from 'zod';
zod.object({
  name: zod.string(),
  neutered: zod.boolean(),
});

Using typescript 3.8.3 with tsConfig:

{
  "compilerOptions": {},
  "include": ["src/**/*"]
}

Finally the message typescript provides:

node_modules/zod/lib/types/object.d.ts:46:43 - error TS2344: Type '{ [k in Exclude<keyof Params, "strict">]: Params[k]; } & { strict: false; }' does not satisfy the constraint 'ZodRawShape'.
  Property 'strict' is incompatible with index signature.
    Type 'false' is not assignable to type 'ZodAny'.

46     nonstrict: () => ZodObject<T, Flatten<{ [k in Exclude<keyof Params, "strict">]: Params[k]; } & {
                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47         strict: false;
   ~~~~~~~~~~~~~~~~~~~~~~
48     }>>;
   ~~~~~

Branded types

Feature request: branded types
This issue can be the primary discussion ground for implemented branded types.

Option 1:
Replicating io-ts's symbol trickery to create types like NonZeroNumber or Email (it might be difficult to do that one while remaining ergonomic)

I don't love all the boilerplate associated with io-ts branded types (i.e. interface PositiveBrand { readonly Positive: unique symbol }).

Option 2

It may be able to include string/number validators as a literal generic argument of the ZodString/ZodNumber classes, like so:

const num: z.number({ max: 5 }) // => z.ZodString
const max5: z.number({ max: 5 }) // => z.ZodString<{ max: 5 }>

That way the validations being enforced are easy to see with a glance at the type definition. This would only work for built-in validators I believe (?). This is also different, in that validations are registered at the instance level instead of the class level.

Unexpected missing key errors with intersections/unions that conflict with inferred type

I'm getting .parse errors that seem incorrect with a schema similar to this one:

z.intersection(
    z.object({
      user: z.object({
        email: z.string(),
        firstName: z.string(),
        lastName: z.string()
      }),
      org: z.object({ name: z.string()})
    }),
    z.union([
      z.object({
        provider: z.literal("email"),
        emailVerificationToken: z.string(),
      }),
      z.object({
        provider: z.enum(["github", "gitlab"]),
        externalAuthSessionId: z.string(),
      }),
    ])
 )

But when using .parse or .check on an object that matches the inferred type, I get missing key errors.

So with a seemingly valid object like this one (that type checks fine with the inferred type):

{
  user: { email: "[email protected]", firstName: "Test", lastName: "User"},
  org: { name: "Test Org" },
  provider: "email",
  emailVerificationToken: "token"  
}

I get the error:

Left side of intersection: Unexpected key(s) in object: 'provider', 'emailVerificationToken'\nRight side of intersection: \n\tunion option #0: Unexpected key(s) in object: 'org', 'user'\n\tunion option #1: Unexpected key(s) in object: 'org', 'user', 'emailVerificationToken'

Is this a bug or am I misunderstanding something about how intersections and unions work in zod?

Type inference incorrectly sets all fields as optional by default

Zod version: 1.5.0
TS version: 3.8.3

The type inference does not seem to be working properly, making all values of objects to be optional by default.

Let me take this code derived from the readme:

import * as z from "zod";

const dogSchema = z.object({
  name: z.string(),
  neutered: z.boolean(),
});

type T = z.TypeOf<typeof dogSchema>;  // -> { name?: string, neutered?: boolean }

const dog: T = {};  // -> Compiles without error

The expected behavior would be a compilation error deriving from name and neutered to be required.

Type-checking methods do not accept `unknown`

As of version 1.2.5, the parse, is and check methods on ZodType expect to receive an argument which is already of the schema's type. This is surprising to me; at version 1.0.15 I was passing unknown values to these functions, since the input is of unknown type (typically from IO) and the functions are being called explicity to discover whether the value matches the type.

Since I don't want to incorrectly-type the values before they are checked, it seems the only option here is to use any, which from my point of view is strictly worse than unknown.

Is there a downside I'm not seeing to permitting unknown as input to these functions?

How to parse Dates in Api with zod

Hi, Great wrok with zod. maybe i'm using it wrong but how would i parse a date in Api params i would get a string of Date and Zod expects a Date object. Should i use the zod.string() and parse the date in the backend?

Enum validation support?

Is it possible right now? related to #3

example:

enum Foo {
  BAR = 'BAR',
  BAZ = 'BAZ'
}
let e = z.enum(Foo);

e.parse("LOL"); // throws

Requesting any and / or unknown types

Coming from io-ts there were useful t.any() or t.unknown() types for accepting anything but not making many assertions about what values contained. Is that something that fits into the Zod vision?

Is it possible to add support for literal types and discriminated unions?

It would be cool if the variation of the below code is allowed:

const CellText = z.object({
  kind: "text",
  body: z.string(),
});

const CellCode = z.object({
  kind: "code",
  code: z.string(),
});

const Schema = z.array(
  z.object({
    category: z.string(),
    cells: z.array(z.union([CellText, CellCode])).nonempty(),
  })
);

Value transformation / object mapping

Hey! I just tried zod and I quite enjoy it so far, great job! I have a feature request/discussion.

Problem: I would like my schema to not only validate data but transform it as well. A particular use case is that I would like to specify a mapping in my object schema.

One could imagine a type z.stringAsNumber() which would parse strings like "123" to a number 123. Something like this is totally possible with io-ts.

Or even more powerful case. Where object validation could remap keys:

const envSchema = z.object({
  SERVER_HOST: z.string(),
  PUBLIC_S3_URL: z.string(),
  PRIVATE_BACKEND_URL: z.string(),
})

This schema is used to validate environment variables. It would be cool if I could specify a key mapping to end up with renamed keys in a parsed object for example (example API)

const envSchema = z.object({
  serverHost: { value: z.string(), key: 'SERVER_HOST' },
  publicS3: { value: z.string(), key: 'PUBLIC_S3_URL' }
  privateBackendURL: { z.string(), key: 'PRIVATE_BACKEND_URL' }
})

I feel like this is a very common situation. Of course, it can be done manually after schema validation but I believe that it would be cool to support this one way or another. WDYT @vriad? Is this something that you want to support eventually?

Can you provide an example of how to do { stripUnknown: true }?

I'm wondering how to do this option from yum:

stripUnknown:remove unspecified keys from objects.

I can pluck or omit, but what if I only want to pick the properties on the ZodObject?

For example:

const Animal = z.object({
 name: z.string(),
}),
export type Animal = z.infer<
  typeof Animal
>;

But, it so happens that an object such as { name: 'tommy', kind: 'cat' } comes along. How do I only validate the properties on Animal and drop others like kind?

Since I am returned the same object and .nonstrict allows me to still verify the keys I care about, I would like to be able to drop the unknown keys that are on the object.

The zod object Animal has a .toJSON which return the shape and I can get keys this way:

Animal.toJSON().shape['0']

Dictionary type: unknown keys but known values

I've looked through the docs, but I'm unclear on how to achieve a dictionary type that has unknown string keys, but known values, basically the type of Record<string, KnownType | undefined>. The nostrict() modifier is close, but I don't see how to specify the value type when using that

z.function can not be used with z.object

version: 1.0.9 | 1.2.5 | 1.5.0

When using z.function with z.object like this:

const MouseEvents = z.object({
    onClick: z.function(z.tuple([z.number()]), z.undefined())
})

Type error throws:
image

Specify valid keys in Record

In TS, I can define an object like so:

type Flags = Record<"flag1"|"flag2", boolean>

or:

type Flags = {[k in "flag1"|"flag2"]: boolean}

It doesn't seem there's any way to accomplish this now in zod? I have lots of TS types using this pattern with large unions that I really don't want to duplicate everywhere as z.object keys, so this would be handy to get full parity with TS.

JSON utility type

I just found myself needing a generic type for any valid JSON and put this together:

type Literal = boolean | null | number | string;
type Json = Literal | { [key: string]: Json } | Json[];

const Literal = Zod.union([Zod.boolean(), Zod.null(), Zod.number(), Zod.string()]);
const Json: Zod.ZodType<Json> = Zod.lazy(() =>
  Zod.union([Literal, Zod.array(Json), Zod.record(Json)])
);

Putting this in an issue for anyone who might be on the lookout or if the library might want to integrate a higher-level utility constructs like this.

Using getters for some functionality?

// Before: `.number()`, `.optional()` etc. as methods
const union = z.union([z.number(), z.boolean()]);
const optionalString = z.string().optional();

// After: `.number()`, `.optional()` etc. as getters
const union = z.union([z.number, z.boolean]);
const optionalString = z.string.optional;

vs Yup

Hi,

I have read your article and reasoning for creating this lib. And I first, ye cool correct types, I will use it.
But then I see that

  1. Is a fraction of yup features
  2. json-schema could be converted to yup
  3. With yup I can insert custom messages
  4. I can do required('this is required')

My question, where do you use it, so you can live without the above features?

Type inference issue for Object schemas

First, Thank you very much for your awesome work ๐Ÿ‘

I figured out when I'm using z.infer on an object schema, the inferred type has all the object's attributes optional. According to the doc, all the attributes should be required.

Example from the doc:

const dogSchema = z.object({
  name: z.string(),
  neutered: z.boolean(),
});

type Dog = z.infer<typeof dogSchema>;

/* 
equivalent to:
type Dog = { 
  name:string; 
  neutered: boolean;
}
*/

But this is what I get:

type Dog = {
    name?: string;
    neutered?: boolean;
}

I'm using zod 1.5.0 and I've also tried with 1.3.0 but keep getting the Dog type with optional attributes.

Thanks for your help!

proper mechanism to integrate with 3rd party types

problem

import { Bananas } from '@fruit/banana'
import * as z from 'zod'
const schema = z.object({
  apple: z.string(),
  banana: z.doSomethingWith3pType() // z.object({}) ??
})
const myType = z.infer<typeof schema> // { apple: string, banana: ???? }

what the best way to get my 3p schema in? assuming because types have been compiled away, getting my 3p schema may not be possible, but, is there a mechanism to put my type into the schema, and get it reflected back out?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.