Comparing version 0.0.11 to 0.0.12
@@ -1,17 +0,34 @@ | ||
import tf, { PascalCase } from "type-fest"; | ||
import { SafeParseReturnType, ZodArray, ZodFunction, ZodLazy, ZodMap, ZodNullable, ZodObject, ZodOptional, ZodPromise, ZodRawShape, ZodRecord, ZodSet, ZodTuple, ZodType, z } from "zod"; | ||
import { PascalCase } from "type-fest"; | ||
import { ParseParams, SafeParseReturnType, ZodArray, ZodFunction, ZodIntersection, ZodLazy, ZodMap, ZodNullable, ZodObject, ZodOptional, ZodPromise, ZodRawShape, ZodRecord, ZodSet, ZodTuple, ZodType, ZodTypeAny, ZodUnion, z } from "zod"; | ||
type Ctor<T = any> = { | ||
new (input: any): T; | ||
}; | ||
export interface ZodClass<Members, Instance, Shape extends ZodRawShape> extends ZodType<Instance> { | ||
export interface ZodClass<Members = any, Instance = any, Shape extends ZodRawShape = ZodRawShape> extends ZodType<Instance> { | ||
shape: Shape; | ||
pick<Mask extends keyof Shape>(...mask: Mask[]): Z.Class<Pick<Shape, Mask>>; | ||
pick<Mask extends { | ||
[property in keyof Shape]?: true | undefined; | ||
}>(mask: Mask): Z.Class<Pick<Shape, { | ||
[property in keyof Mask]: Mask[property] extends true ? Extract<property, keyof Shape> : never; | ||
}[keyof Mask]>>; | ||
omit<Mask extends keyof Shape>(...mask: Mask[]): Z.Class<Omit<Shape, Mask>>; | ||
omit<Mask extends { | ||
[property in keyof Shape]?: true | undefined; | ||
}>(mask: Mask): Z.Class<Omit<Shape, { | ||
[property in keyof Mask]: Mask[property] extends true ? Extract<property, keyof Shape> : never; | ||
}[keyof Mask]>>; | ||
schema<T>(this: Ctor<T>): z.ZodType<T>; | ||
extend<Super extends Ctor, ChildShape extends ZodRawShape>(this: Super, shape: ChildShape): StaticProperties<ChildShape> & { | ||
[k in keyof Super]: Super[k]; | ||
} & ZodClass<Z.infer<ZodObject<ChildShape>> & ConstructorParameters<Super>[0], Z.infer<ZodObject<ChildShape>> & InstanceType<Super>, Omit<Shape, keyof ChildShape> & ChildShape>; | ||
optional<Self extends ZodTypeAny>(this: Self): ZodOptional<Self>; | ||
nullable<Self extends ZodTypeAny>(this: Self): ZodNullable<Self>; | ||
array<Self extends ZodType>(this: Self): ZodArray<Self>; | ||
promise<Self extends ZodType>(this: Self): ZodPromise<Self>; | ||
or<Self extends ZodType, Other extends ZodType>(this: Self, other: Other): ZodUnion<[Self, Other]>; | ||
and<Self extends ZodType, Other extends ZodType>(this: Self, other: Other): ZodIntersection<Self, Other>; | ||
parse<T>(this: Ctor<T>, value: unknown): T; | ||
parseAsync<T>(this: Ctor<T>, value: unknown): Promise<T>; | ||
safeParse<T, V>(this: Ctor<T>, value: V): SafeParseReturnType<V, T>; | ||
safeParseAsync<T, V>(this: Ctor<T>, value: V): Promise<SafeParseReturnType<V, T>>; | ||
optional<Self extends ZodType>(this: Self): ZodOptional<Self>; | ||
nullable<Self extends ZodType>(this: Self): ZodNullable<Self>; | ||
safeParse<T>(this: Ctor<T>, data: unknown, params?: Partial<ParseParams>): SafeParseReturnType<Instance, T>; | ||
safeParseAsync<T, V>(this: Ctor<T>, data: unknown, params?: Partial<ParseParams>): Promise<SafeParseReturnType<Instance, T>>; | ||
new (data: Members): Instance; | ||
@@ -37,8 +54,11 @@ } | ||
export interface Z { | ||
class<Shape extends ZodRawShape>(shape: Shape): StaticProperties<Shape> & ZodClass<Z.infer<ZodObject<Shape>>, Z.infer<ZodObject<Shape>>, Shape>; | ||
class<Shape extends ZodRawShape>(shape: Shape): Z.Class<Shape>; | ||
} | ||
export declare namespace Z { | ||
type Class<Shape extends ZodRawShape> = StaticProperties<Shape> & ZodClass<Z.infer<ZodObject<Shape>>, Z.infer<ZodObject<Shape>>, Shape>; | ||
} | ||
export declare const Z: { | ||
class<T extends ZodRawShape>(shape: T): { [property in keyof T as tf.PascalCase<property>]: T[property]; } & ZodClass<{ [k in keyof T]: Z.infer<T[k]>; }, { [k_1 in keyof Pick<T, Exclude<keyof T, OptionalKeys<T>>>]: Z.infer<T[k_1]>; } & { [k_2 in OptionalKeys<T>]+?: Z.infer<T[k_2]>; }, T>; | ||
class<T extends ZodRawShape>(shape: T): { [property in keyof T as PascalCase<property>]: T[property]; } & ZodClass<{ [k in keyof T]: Z.infer<T[k]>; }, { [k_1 in keyof Pick<T, Exclude<keyof T, OptionalKeys<T>>>]: Z.infer<T[k_1]>; } & { [k_2 in OptionalKeys<T>]+?: Z.infer<T[k_2]>; }, T>; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -10,2 +10,3 @@ "use strict"; | ||
const to_pascal_case_js_1 = require("./to-pascal-case.js"); | ||
const types_1 = require("util/types"); | ||
const IS_ZOD_CLASS = Symbol.for("zod-class"); | ||
@@ -15,10 +16,12 @@ exports.Z = { | ||
var _a, _b; | ||
const _schema = (0, zod_1.object)(shape); | ||
const clazz = (_a = class { | ||
static schema() { | ||
return this; | ||
} | ||
constructor(value) { | ||
Object.assign(this, _schema.parse(value)); | ||
Object.assign(this, clazz._schema.parse(value)); | ||
} | ||
static extend(augmentation) { | ||
var _c; | ||
const augmented = this.schema.extend(augmentation); | ||
const augmented = this._schema.extend(augmentation); | ||
// @ts-ignore | ||
@@ -32,3 +35,4 @@ const clazz = (_c = class extends this { | ||
__setFunctionName(_c, "clazz"), | ||
_c.schema = augmented, | ||
_c.shape = augmented.shape, | ||
_c._schema = augmented, | ||
_c); | ||
@@ -38,2 +42,39 @@ Object.assign(clazz, getStaticMembers(augmentation)); | ||
} | ||
// can NOT create a sub-type | ||
static pick(mask, ...masks) { | ||
if (typeof mask === "string") { | ||
return exports.Z.class(this._schema.pick({ | ||
[mask]: true, | ||
...Object.fromEntries(masks.map((m) => [m, true])), | ||
}).shape); | ||
} | ||
else { | ||
return exports.Z.class(this._schema.pick(mask).shape); | ||
} | ||
} | ||
static omit(mask, ...masks) { | ||
if (typeof mask === "string") { | ||
return exports.Z.class(this._schema.omit({ | ||
[mask]: true, | ||
...Object.fromEntries(masks.map((m) => [m, true])), | ||
}).shape); | ||
} | ||
else { | ||
return exports.Z.class(this._schema.omit(mask).shape); | ||
} | ||
} | ||
// CAN create a sub-type | ||
static required() { | ||
return this.extend(this._schema.required().shape); | ||
} | ||
static strict() { | ||
return this.extend(this._schema.strict().shape); | ||
} | ||
static strip() { | ||
return this.extend(this._schema.strip().shape); | ||
} | ||
static catchall(type) { | ||
return this.extend(this._schema.catchall(type).shape); | ||
} | ||
// combinators | ||
static optional() { | ||
@@ -45,15 +86,53 @@ return new zod_1.ZodOptional(this); | ||
} | ||
static nullish() { | ||
return this.optional().nullable(); | ||
} | ||
static array() { | ||
return new zod_1.ZodArray(this); | ||
} | ||
static promise() { | ||
return new zod_1.ZodPromise(this); | ||
} | ||
static or(other) { | ||
return zod_1.z.union([this, other]); | ||
} | ||
static and(other) { | ||
return zod_1.z.intersection(this, other); | ||
} | ||
// TODO: | ||
// static transform() | ||
// static default | ||
// static brand | ||
// static catch | ||
static describe(description) { } | ||
static parse(value, params) { | ||
return new this(this.schema.parse(value, params)); | ||
return new this(this._schema.parse(value, params)); | ||
} | ||
static parseAsync(value, params) { | ||
return this.schema | ||
return this._schema | ||
.parseAsync(value, params) | ||
.then((value) => new this(value)); | ||
} | ||
static _parse(input) { | ||
const result = this._schema._parse(input); | ||
if ((0, types_1.isPromise)(result)) { | ||
return result.then((result) => _coerceParseResult(this, result)); | ||
} | ||
else { | ||
return _coerceParseResult(this, result); | ||
} | ||
} | ||
static _parseSync(input) { | ||
return _coerceParseResult(this, this._schema._parseSync(input)); | ||
} | ||
static _parseAsync(input) { | ||
return this._schema | ||
._parseAsync(input) | ||
.then((result) => _coerceParseResult(this, result)); | ||
} | ||
static safeParse(value, params) { | ||
return coerceSafeParse(this, this.schema.safeParse(value, params)); | ||
return coerceSafeParse(this, this._schema.safeParse(value, params)); | ||
} | ||
static safeParseAsync(value, params) { | ||
return this.schema | ||
return this._schema | ||
.safeParseAsync(value, params) | ||
@@ -66,6 +145,9 @@ .then((result) => coerceSafeParse(this, result)); | ||
_a[_b] = true, | ||
_a.schema = _schema, | ||
_a.shape = shape, | ||
_a._parse = _a.schema._parse.bind(_a.schema), | ||
_a._parseSync = _a.schema._parseSync.bind(_a.schema), | ||
_a._schema = (0, zod_1.object)(shape), | ||
_a.merge = _a.extend.bind(_a), | ||
_a.partial = (mask) => _a._schema.partial(mask), | ||
_a.deepPartial = () => _a._schema.deepPartial(), | ||
_a.passthrough = () => _a._schema.passthrough(), | ||
_a.keyof = () => _a._schema.keyof(), | ||
_a); | ||
@@ -90,2 +172,13 @@ Object.assign(clazz, getStaticMembers(shape)); | ||
} | ||
function _coerceParseResult(cls, result) { | ||
if (result.status === "valid" || result.status === "dirty") { | ||
return { | ||
status: result.status, | ||
value: new cls(result.value), | ||
}; | ||
} | ||
else { | ||
return result; | ||
} | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -1,17 +0,34 @@ | ||
import tf, { PascalCase } from "type-fest"; | ||
import { SafeParseReturnType, ZodArray, ZodFunction, ZodLazy, ZodMap, ZodNullable, ZodObject, ZodOptional, ZodPromise, ZodRawShape, ZodRecord, ZodSet, ZodTuple, ZodType, z } from "zod"; | ||
import { PascalCase } from "type-fest"; | ||
import { ParseParams, SafeParseReturnType, ZodArray, ZodFunction, ZodIntersection, ZodLazy, ZodMap, ZodNullable, ZodObject, ZodOptional, ZodPromise, ZodRawShape, ZodRecord, ZodSet, ZodTuple, ZodType, ZodTypeAny, ZodUnion, z } from "zod"; | ||
type Ctor<T = any> = { | ||
new (input: any): T; | ||
}; | ||
export interface ZodClass<Members, Instance, Shape extends ZodRawShape> extends ZodType<Instance> { | ||
export interface ZodClass<Members = any, Instance = any, Shape extends ZodRawShape = ZodRawShape> extends ZodType<Instance> { | ||
shape: Shape; | ||
pick<Mask extends keyof Shape>(...mask: Mask[]): Z.Class<Pick<Shape, Mask>>; | ||
pick<Mask extends { | ||
[property in keyof Shape]?: true | undefined; | ||
}>(mask: Mask): Z.Class<Pick<Shape, { | ||
[property in keyof Mask]: Mask[property] extends true ? Extract<property, keyof Shape> : never; | ||
}[keyof Mask]>>; | ||
omit<Mask extends keyof Shape>(...mask: Mask[]): Z.Class<Omit<Shape, Mask>>; | ||
omit<Mask extends { | ||
[property in keyof Shape]?: true | undefined; | ||
}>(mask: Mask): Z.Class<Omit<Shape, { | ||
[property in keyof Mask]: Mask[property] extends true ? Extract<property, keyof Shape> : never; | ||
}[keyof Mask]>>; | ||
schema<T>(this: Ctor<T>): z.ZodType<T>; | ||
extend<Super extends Ctor, ChildShape extends ZodRawShape>(this: Super, shape: ChildShape): StaticProperties<ChildShape> & { | ||
[k in keyof Super]: Super[k]; | ||
} & ZodClass<Z.infer<ZodObject<ChildShape>> & ConstructorParameters<Super>[0], Z.infer<ZodObject<ChildShape>> & InstanceType<Super>, Omit<Shape, keyof ChildShape> & ChildShape>; | ||
optional<Self extends ZodTypeAny>(this: Self): ZodOptional<Self>; | ||
nullable<Self extends ZodTypeAny>(this: Self): ZodNullable<Self>; | ||
array<Self extends ZodType>(this: Self): ZodArray<Self>; | ||
promise<Self extends ZodType>(this: Self): ZodPromise<Self>; | ||
or<Self extends ZodType, Other extends ZodType>(this: Self, other: Other): ZodUnion<[Self, Other]>; | ||
and<Self extends ZodType, Other extends ZodType>(this: Self, other: Other): ZodIntersection<Self, Other>; | ||
parse<T>(this: Ctor<T>, value: unknown): T; | ||
parseAsync<T>(this: Ctor<T>, value: unknown): Promise<T>; | ||
safeParse<T, V>(this: Ctor<T>, value: V): SafeParseReturnType<V, T>; | ||
safeParseAsync<T, V>(this: Ctor<T>, value: V): Promise<SafeParseReturnType<V, T>>; | ||
optional<Self extends ZodType>(this: Self): ZodOptional<Self>; | ||
nullable<Self extends ZodType>(this: Self): ZodNullable<Self>; | ||
safeParse<T>(this: Ctor<T>, data: unknown, params?: Partial<ParseParams>): SafeParseReturnType<Instance, T>; | ||
safeParseAsync<T, V>(this: Ctor<T>, data: unknown, params?: Partial<ParseParams>): Promise<SafeParseReturnType<Instance, T>>; | ||
new (data: Members): Instance; | ||
@@ -37,8 +54,11 @@ } | ||
export interface Z { | ||
class<Shape extends ZodRawShape>(shape: Shape): StaticProperties<Shape> & ZodClass<Z.infer<ZodObject<Shape>>, Z.infer<ZodObject<Shape>>, Shape>; | ||
class<Shape extends ZodRawShape>(shape: Shape): Z.Class<Shape>; | ||
} | ||
export declare namespace Z { | ||
type Class<Shape extends ZodRawShape> = StaticProperties<Shape> & ZodClass<Z.infer<ZodObject<Shape>>, Z.infer<ZodObject<Shape>>, Shape>; | ||
} | ||
export declare const Z: { | ||
class<T extends ZodRawShape>(shape: T): { [property in keyof T as tf.PascalCase<property>]: T[property]; } & ZodClass<{ [k in keyof T]: Z.infer<T[k]>; }, { [k_1 in keyof Pick<T, Exclude<keyof T, OptionalKeys<T>>>]: Z.infer<T[k_1]>; } & { [k_2 in OptionalKeys<T>]+?: Z.infer<T[k_2]>; }, T>; | ||
class<T extends ZodRawShape>(shape: T): { [property in keyof T as PascalCase<property>]: T[property]; } & ZodClass<{ [k in keyof T]: Z.infer<T[k]>; }, { [k_1 in keyof Pick<T, Exclude<keyof T, OptionalKeys<T>>>]: Z.infer<T[k_1]>; } & { [k_2 in OptionalKeys<T>]+?: Z.infer<T[k_2]>; }, T>; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,4 +5,5 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { | ||
}; | ||
import { ZodNullable, ZodOptional, object, } from "zod"; | ||
import { ZodArray, ZodNullable, ZodOptional, ZodPromise, object, z, } from "zod"; | ||
import { toPascalCase } from "./to-pascal-case.js"; | ||
import { isPromise } from "util/types"; | ||
const IS_ZOD_CLASS = Symbol.for("zod-class"); | ||
@@ -12,10 +13,12 @@ export const Z = { | ||
var _a, _b; | ||
const _schema = object(shape); | ||
const clazz = (_a = class { | ||
static schema() { | ||
return this; | ||
} | ||
constructor(value) { | ||
Object.assign(this, _schema.parse(value)); | ||
Object.assign(this, clazz._schema.parse(value)); | ||
} | ||
static extend(augmentation) { | ||
var _c; | ||
const augmented = this.schema.extend(augmentation); | ||
const augmented = this._schema.extend(augmentation); | ||
// @ts-ignore | ||
@@ -29,3 +32,4 @@ const clazz = (_c = class extends this { | ||
__setFunctionName(_c, "clazz"), | ||
_c.schema = augmented, | ||
_c.shape = augmented.shape, | ||
_c._schema = augmented, | ||
_c); | ||
@@ -35,2 +39,39 @@ Object.assign(clazz, getStaticMembers(augmentation)); | ||
} | ||
// can NOT create a sub-type | ||
static pick(mask, ...masks) { | ||
if (typeof mask === "string") { | ||
return Z.class(this._schema.pick({ | ||
[mask]: true, | ||
...Object.fromEntries(masks.map((m) => [m, true])), | ||
}).shape); | ||
} | ||
else { | ||
return Z.class(this._schema.pick(mask).shape); | ||
} | ||
} | ||
static omit(mask, ...masks) { | ||
if (typeof mask === "string") { | ||
return Z.class(this._schema.omit({ | ||
[mask]: true, | ||
...Object.fromEntries(masks.map((m) => [m, true])), | ||
}).shape); | ||
} | ||
else { | ||
return Z.class(this._schema.omit(mask).shape); | ||
} | ||
} | ||
// CAN create a sub-type | ||
static required() { | ||
return this.extend(this._schema.required().shape); | ||
} | ||
static strict() { | ||
return this.extend(this._schema.strict().shape); | ||
} | ||
static strip() { | ||
return this.extend(this._schema.strip().shape); | ||
} | ||
static catchall(type) { | ||
return this.extend(this._schema.catchall(type).shape); | ||
} | ||
// combinators | ||
static optional() { | ||
@@ -42,15 +83,53 @@ return new ZodOptional(this); | ||
} | ||
static nullish() { | ||
return this.optional().nullable(); | ||
} | ||
static array() { | ||
return new ZodArray(this); | ||
} | ||
static promise() { | ||
return new ZodPromise(this); | ||
} | ||
static or(other) { | ||
return z.union([this, other]); | ||
} | ||
static and(other) { | ||
return z.intersection(this, other); | ||
} | ||
// TODO: | ||
// static transform() | ||
// static default | ||
// static brand | ||
// static catch | ||
static describe(description) { } | ||
static parse(value, params) { | ||
return new this(this.schema.parse(value, params)); | ||
return new this(this._schema.parse(value, params)); | ||
} | ||
static parseAsync(value, params) { | ||
return this.schema | ||
return this._schema | ||
.parseAsync(value, params) | ||
.then((value) => new this(value)); | ||
} | ||
static _parse(input) { | ||
const result = this._schema._parse(input); | ||
if (isPromise(result)) { | ||
return result.then((result) => _coerceParseResult(this, result)); | ||
} | ||
else { | ||
return _coerceParseResult(this, result); | ||
} | ||
} | ||
static _parseSync(input) { | ||
return _coerceParseResult(this, this._schema._parseSync(input)); | ||
} | ||
static _parseAsync(input) { | ||
return this._schema | ||
._parseAsync(input) | ||
.then((result) => _coerceParseResult(this, result)); | ||
} | ||
static safeParse(value, params) { | ||
return coerceSafeParse(this, this.schema.safeParse(value, params)); | ||
return coerceSafeParse(this, this._schema.safeParse(value, params)); | ||
} | ||
static safeParseAsync(value, params) { | ||
return this.schema | ||
return this._schema | ||
.safeParseAsync(value, params) | ||
@@ -63,6 +142,9 @@ .then((result) => coerceSafeParse(this, result)); | ||
_a[_b] = true, | ||
_a.schema = _schema, | ||
_a.shape = shape, | ||
_a._parse = _a.schema._parse.bind(_a.schema), | ||
_a._parseSync = _a.schema._parseSync.bind(_a.schema), | ||
_a._schema = object(shape), | ||
_a.merge = _a.extend.bind(_a), | ||
_a.partial = (mask) => _a._schema.partial(mask), | ||
_a.deepPartial = () => _a._schema.deepPartial(), | ||
_a.passthrough = () => _a._schema.passthrough(), | ||
_a.keyof = () => _a._schema.keyof(), | ||
_a); | ||
@@ -87,2 +169,13 @@ Object.assign(clazz, getStaticMembers(shape)); | ||
} | ||
function _coerceParseResult(cls, result) { | ||
if (result.status === "valid" || result.status === "dirty") { | ||
return { | ||
status: result.status, | ||
value: new cls(result.value), | ||
}; | ||
} | ||
else { | ||
return result; | ||
} | ||
} | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "zod-class", | ||
"description": "Create classes from Zod Object schemas all in one line", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"repository": { | ||
@@ -21,3 +21,3 @@ "url": "https://github.com/sam-goodwin/zod-class" | ||
"build": "tsc -b", | ||
"test": "NODE_OPTIONS=--experimental-vm-modules jest", | ||
"test": "NODE_OPTIONS=--experimental-vm-modules jest && cd ./test/pkg && pnpm i && pnpm build", | ||
"watch": "tsc -b -w" | ||
@@ -24,0 +24,0 @@ }, |
@@ -103,1 +103,51 @@ # zod-class | ||
## Workarounds | ||
Creating a class that adequately sub-types a Zod Schema is difficult because of how Zod is implemented. `zod-class` covers the most common use-cases but there are holes. | ||
If you encounter a problem with type errors, you can always workaround it with the `schema()` method. | ||
For example, if you have a function that expects a `ZodType<T>`: | ||
```ts | ||
function createDTO<T>(schema: ZodType<T>): DTO<T>; | ||
``` | ||
And a class, `User`, constructed with `Z.class`: | ||
```ts | ||
class User extends Z.class({ | ||
username: z.string() | ||
}) {} | ||
``` | ||
You should be able to just pass `User` in | ||
```ts | ||
const UserDTO = createDTO(User); | ||
``` | ||
In some cases, this can error. To workaround, call `User.schema()` instead: | ||
```ts | ||
const UserDTO = createDTO(User.schema()); | ||
``` | ||
See relevant issue: [#17](https://github.com/sam-goodwin/zod-class/issues/17) | ||
2. `nullish` will not create a schema that returns an instance of the ZodClass | ||
ZodClass does not provide a type-safe implementation of `schema.nullish()`. | ||
```ts | ||
User.nullish().parse(value) | ||
``` | ||
This will not return an instance of `User`: | ||
```ts | ||
{ username: string } | null | undefined | ||
``` | ||
Workaround with `User.schema()` | ||
```ts | ||
User.schema().nullish().parse(value) // User | null | undefined | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
152802
497
152