Skip to content

Instantly share code, notes, and snippets.

@alirezas
Created November 8, 2023 18:33
Show Gist options
  • Save alirezas/1500122bda1b1621946d65f546df8ff5 to your computer and use it in GitHub Desktop.
Save alirezas/1500122bda1b1621946d65f546df8ff5 to your computer and use it in GitHub Desktop.
interface ZodString {
type: "string",
parse(val: unknown): string
}
interface ZodNumber {
type: "number",
parse(val: unknown): number
}
interface ZodUnknown {
type: "unknown",
parse(val: unknown): unknown
}
interface ZodArray<T extends ZodType> {
type: "array",
element: T,
parse(val: unknown): Array<Infer<T>>
}
interface ZodObject<T extends Record<string, ZodType>> {
type: "object",
fields: T,
parse(val: unknown): InferZodObject<ZodObject<T>>
}
type ZodType = ZodString | ZodNumber | ZodUnknown | ZodArray<ZodType> | ZodObject<Record<string, ZodType>>
type InferZodObject<T extends ZodObject<Record<string, ZodType>>> = {
[Key in keyof T["fields"]]: Infer<T["fields"][Key]>
}
type Infer<T extends ZodType> =
T extends ZodUnknown ?
unknown :
T extends ZodString ?
string :
T extends ZodNumber ?
number :
T extends ZodArray<infer E> ?
Array<Infer<E>> :
T extends ZodObject<Record<string, ZodType>> ?
InferZodObject<T> :
"invalid type"
const string = (): ZodString => ({
type: "string",
parse(val): string {
if (typeof val !== "string") throw new Error("Not a string")
return val
}
})
const number = (): ZodNumber => ({
type: "number",
parse(val): number {
if (typeof val !== "number") throw new Error("Not a number")
return val
}
})
const unknown = (): ZodUnknown => ({
type: "unknown",
parse(val): unknown { return val }
})
const array = <T extends ZodType>(element: T): ZodArray<T> => ({
type: "array",
element,
parse(val): Array<Infer<T>> {
if (!Array.isArray(val)) throw new Error("Not an array")
val.forEach((v) => this.element.parse(v))
return val
}
})
const object = <T extends Record<string, ZodType>>(fields: T): ZodObject<T> => ({
type: "object",
fields,
parse(val): InferZodObject<ZodObject<T>> {
if (typeof val !== "object" || val == null) throw new Error("Not an object")
const recordVal = val as Record<string, unknown>
Object.entries(this.fields).forEach(([k, v]) => v.parse(recordVal[k]))
return val as InferZodObject<ZodObject<T>>
}
})
export const z = {
string,
number,
unknown,
array,
object
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment