diff --git a/src/ZodSchemaClass.ts b/src/ZodSchemaClass.ts new file mode 100644 index 0000000..4dc580d --- /dev/null +++ b/src/ZodSchemaClass.ts @@ -0,0 +1,176 @@ +import { AbstractClass, Class as ConcreteClass, Opaque } from "type-fest" +import { z } from "zod" +import { DefinedDefaultValuesTag } from "." +import { StaticMembers } from "./util" + + +export type TZodSchemaClass< + Schema extends z.ZodObject, + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + Values extends {}, + DefaultValues extends Partial, +> = ( + AbstractClass< + { + readonly schema: Schema + readonly defaultValues: DefaultValues + } & Values, + + [values: Values] + > & { + readonly schema: Schema + readonly defaultValues: DefaultValues + + newPromise>(this: Self): Promise> + + extend< + Parent + >( + this: Parent + ): Parent + } +) + + +type ExtendableClass = AbstractClass<{ + schema?: never + defaultValues?: never +}, []> & { + schema?: never + defaultValues?: never +} + +function makeClass< + Self, + Parent extends ExtendableClass, + + Schema extends z.ZodObject, + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + Values extends {}, + DefaultValues extends Partial, +>( + { of, schema, defaultValues }: { + self: Self, + of: Parent, + schema: Schema | z.ZodObject + defaultValues: Opaque + }, +) { + type Class = ( + Parent extends ConcreteClass + ? ConcreteClass + : AbstractClass + ) + + type ZodClass = TZodSchemaClass< + Schema, + SchemaT, + SchemaUnknownKeys, + SchemaCatchall, + + Values, + DefaultValues + > + + return class extends (of as unknown as ConcreteClass) { + static readonly schema = schema + readonly schema = schema + + static readonly defaultValues = defaultValues + readonly defaultValues = defaultValues + + constructor(values: Values) { + super() + Object.assign(this, values) + } + } as unknown as ( + Class< + InstanceType & + InstanceType, + + ConstructorParameters + > & + + StaticMembers & + StaticMembers + ) +} + + +export function ZodSchemaClassOf() { + return < + Parent extends ExtendableClass, + + Schema extends z.ZodObject, + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + Values extends {}, + DefaultValues extends Partial, + >( + of: Parent, + props: Omit< + Parameters< + typeof makeClass< + Self, + Parent, + + Schema, + SchemaT, + SchemaUnknownKeys, + SchemaCatchall, + + Values, + DefaultValues + > + >[0], "self" | "of" + >, + ) => makeClass({ + ...props, + self: {} as Self, + of, + }) +} + + +const DefaultParent = Object + +export function ZodSchemaClass() { + return < + Schema extends z.ZodObject, + SchemaT extends z.ZodRawShape, + SchemaUnknownKeys extends z.UnknownKeysParam, + SchemaCatchall extends z.ZodTypeAny, + + Values extends {}, + DefaultValues extends Partial, + >( + props: Omit< + Parameters< + typeof makeClass< + Self, + typeof DefaultParent, + + Schema, + SchemaT, + SchemaUnknownKeys, + SchemaCatchall, + + Values, + DefaultValues + > + >[0], "self" | "of" + >, + ) => makeClass({ + ...props, + self: {} as Self, + of: DefaultParent, + }) +} diff --git a/src/defineDefaultValues.ts b/src/defineDefaultValues.ts new file mode 100644 index 0000000..634d83a --- /dev/null +++ b/src/defineDefaultValues.ts @@ -0,0 +1,8 @@ +import { Opaque } from "type-fest" + + +export type DefinedDefaultValuesTag = "@thilawyn/schemable-class/DefinedDefaultValues" + +export function defineDefaultValues(values: T) { + return values as Opaque +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..8302d95 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,2 @@ +export * from "./ZodSchemaClass" +export * from "./defineDefaultValues" diff --git a/src/tests.ts b/src/tests.ts index e69de29..39bfb8f 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -0,0 +1,26 @@ +import { z } from "zod" +import { ZodSchemaClassOf, defineDefaultValues } from "." + + +class Test extends ZodSchemaClassOf()(Object, { + schema: z.object({ + id: z.bigint() + }), + + defaultValues: defineDefaultValues({ id: -1n }), +}) {} +Test.newPromise() +Test.extend() + +new Test({ id: 1n }).id + + +const Test2 = ZodSchemaClassOf()(Object, { + schema: z.object({ + id: z.bigint() + }), + + defaultValues: defineDefaultValues({ id: -1n }), +}) + +Test2.extend()