diff --git a/src/TZodSchemaClass.ts b/src/TZodSchemaClass.ts index be2a64a..72e665f 100644 --- a/src/TZodSchemaClass.ts +++ b/src/TZodSchemaClass.ts @@ -1,6 +1,8 @@ -import { Class as ConcreteClass, HasRequiredKeys } from "type-fest" +import { Effect } from "effect" +import { AbstractClass, Class as ConcreteClass, HasRequiredKeys, Opaque } from "type-fest" import { z } from "zod" -import { Class, ClassType } from "./util" +import { DefinedDefaultValuesTag } from "." +import { Class, ClassType, StaticMembers } from "./util" export type NewZodSchemaInstanceInput< @@ -22,8 +24,23 @@ export type NewZodSchemaInstanceArgs = : [] | [values: Input, ...args: ParseParamsArgs] +type ExtendZodSchemaClass< + Parent extends AbstractClass, + Self extends AbstractClass, +> = ( + AbstractClass< + Omit, keyof InstanceType> & + InstanceType, + + ConstructorParameters + > & + + Omit & + StaticMembers +) + + export type TZodSchemaClass< - Schema extends z.ZodObject, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, @@ -38,7 +55,7 @@ export type TZodSchemaClass< Values, [values: Values] > & { - readonly schema: Schema + readonly schema: z.ZodObject readonly defaultValues: DefaultValues instantiate>( @@ -60,12 +77,48 @@ export type TZodSchemaClass< ...[values, params]: NewZodSchemaInstanceArgs< NewZodSchemaInstanceInput > - ): Promise> + ): Effect.Effect, Values> extend< - Parent + Parent extends AbstractClass, + + ExtendedSchemaT extends z.ZodRawShape, + ExtendedSchemaUnknownKeys extends z.UnknownKeysParam, + ExtendedSchemaCatchall extends z.ZodTypeAny, + + ExtendedValues extends Values, + ExtendedDefaultValues extends Partial, >( - this: Parent - ): Parent + this: Parent, + + props: { + schema: (props: { + schema: z.ZodObject + shape: SchemaT + }) => z.ZodObject + + defaultValues: (defaultValues: DefaultValues) => Opaque + }, + ): ExtendZodSchemaClass< + Parent, + + TZodSchemaClass< + ExtendedSchemaT, + ExtendedSchemaUnknownKeys, + ExtendedSchemaCatchall, + + ExtendedValues, + ExtendedDefaultValues + > + > } ) + +export type DefaultZodSchemaClass = TZodSchemaClass< + z.ZodRawShape, + z.UnknownKeysParam, + z.ZodTypeAny, + + {}, + {} +> diff --git a/src/ZodSchemaClass.ts b/src/ZodSchemaClass.ts index 3664b57..39c3c9a 100644 --- a/src/ZodSchemaClass.ts +++ b/src/ZodSchemaClass.ts @@ -1,7 +1,8 @@ +import { Effect, pipe } from "effect" import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest" import { z } from "zod" import { DefinedDefaultValuesTag, NewZodSchemaInstanceArgs, NewZodSchemaInstanceInput, TZodSchemaClass } from "." -import { StaticMembers } from "./util" +import { StaticMembers, parseZodTypeEffect } from "./util" type ExtendableClass = AbstractClass & { @@ -12,7 +13,6 @@ type ExtendableClass = AbstractClass & { export function ZodSchemaClassOf< Parent extends ExtendableClass, - Schema extends z.ZodObject, SchemaT extends z.ZodRawShape, SchemaUnknownKeys extends z.UnknownKeysParam, SchemaCatchall extends z.ZodTypeAny, @@ -23,7 +23,7 @@ export function ZodSchemaClassOf< of: Parent, { schema, defaultValues }: { - schema: Schema | z.ZodObject + schema: z.ZodObject defaultValues: Opaque }, ) { @@ -34,7 +34,6 @@ export function ZodSchemaClassOf< ) type TZodSchemaClassImpl = TZodSchemaClass< - Schema, SchemaT, SchemaUnknownKeys, SchemaCatchall, @@ -44,7 +43,7 @@ export function ZodSchemaClassOf< > return class extends (of as unknown as ConcreteClass) { - static readonly schema = schema + static readonly schema = schema static readonly defaultValues = defaultValues constructor(values: Values) { @@ -52,7 +51,7 @@ export function ZodSchemaClassOf< Object.assign(this, values) } - static async instantiate( + static instantiate( ...[values, params]: NewZodSchemaInstanceArgs< NewZodSchemaInstanceInput > @@ -71,6 +70,52 @@ export function ZodSchemaClassOf< await this.schema.parseAsync({ ...this.defaultValues, ...values }, params) ) } + + static instantiateEffect( + ...[values, params]: NewZodSchemaInstanceArgs< + NewZodSchemaInstanceInput + > + ) { + return pipe( + parseZodTypeEffect( + this.schema, + { ...this.defaultValues, ...values }, + params, + ), + + Effect.map(values => new this(values)), + ) + } + + static extend< + ExtendedSchemaT extends z.ZodRawShape, + ExtendedSchemaUnknownKeys extends z.UnknownKeysParam, + ExtendedSchemaCatchall extends z.ZodTypeAny, + + ExtendedValues extends Values, + ExtendedDefaultValues extends Partial, + >( + props: { + schema: (props: { + schema: z.ZodObject + shape: SchemaT + }) => z.ZodObject + + defaultValues: (defaultValues: DefaultValues) => Opaque + }, + ) { + const schema = props.schema({ + schema: this.schema, + shape: this.schema.shape, + }) + + const defaultValues = props.defaultValues(this.defaultValues) + + return class extends (this as unknown as ConcreteClass) { + static readonly schema = schema + static readonly defaultValues = defaultValues + } + } } as unknown as ( Class< InstanceType & diff --git a/src/tests.ts b/src/tests.ts index 7f4befd..de23363 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -14,12 +14,24 @@ class Test extends ZodSchemaClassOf(Root, { defaultValues: defineDefaultValues({ id: -1n }), }) {} + Test.defaultValues const inst = await Test.instantiatePromise({ id: 1n, name: "" }) -// Test.extend() -console.log(inst) +class SubTest extends Test.extend({ + schema: ({ schema }) => schema.extend({ + prout: z.string() + }), -class ChildTest extends Test {} + defaultValues: defaultValues => defineDefaultValues({ + ...defaultValues + }), +}) {} -ChildTest.instantiate({ name: "" }) +const subInst = await SubTest.instantiatePromise({ name: "", prout: "" }) + +console.log(subInst) + +// class ChildTest extends Test {} + +// ChildTest.instantiate({ name: "" })