Skip to content

LaysDragon/zod-schema-mapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zod Schema Mapper

zod schema type mapper,its can create new schema base on existed zod schema with condition type tester.

Example

Schema

export const dataSchema = z.object({
  id: z.string(),
  age: z.number(),
  createdAt: z.date(),
  arrayDate: z.date().array(),
  arrayNumber: z.number().array(),
  testUnion: z.number().or(z.date()),
});

export type Data = z.infer<typeof dataSchema>;
// type Data = {
//   id: string;
//   age: number;
//   createdAt: Date;
//   arrayDate: Date[];
//   arrayNumber: number[];
//   testUnion: number | Date;
// }

export const data: Data = {
  age: 1,
  id: "1",
  createdAt: new Date("2024-12-31T10:51:52.587Z"),
  arrayDate: [new Date("2024-12-31T10:51:52.587Z")],
  arrayNumber: [1, 2, 3],
  testUnion: 1,
};

Single Converter

const jsonSchema = convertSchema(
  dataSchema,
  (schema) => schema instanceof z.ZodDate,
  (schema) => schema.transform((value) => value.toISOString())
)
  .convert(
    (schema) => schema instanceof z.ZodNumber,
    (schema) => schema.transform((value) => value.toString())
  )
  .schema();

type Json = z.infer<typeof jsonSchema>;
// type Json = {
//   id: string;
//   age: string;
//   createdAt: string;
//   arrayDate: string[];
//   arrayNumber: string[];
//   testUnion: string;
// }

console.log(jsonSchema.parse(data));
// {
//   id: '1',
//   age: '1',
//   createdAt: '2024-12-31T10:51:52.587Z',
//   arrayDate: [ '2024-12-31T10:51:52.587Z' ],
//   arrayNumber: [ '1', '2', '3' ],
//   testUnion: '1'
// }

Mapper

const jsonMapper = createMapper(
  dataSchema,
  (schema) => schema instanceof z.ZodDate,
  (schema) => schema.transform((value) => value.toISOString()),
  (schema) =>
    z
      .string()
      .datetime()
      .transform((value) => new Date(value))
      .pipe(schema)
)
  .create(
    (schema) => schema instanceof z.ZodNumber,
    (schema) => schema.transform((value) => value.toString()),
    (schema) =>
      z
        .string()
        .transform((value) => Number(value))
        .pipe(schema)
  )
  .mapper();

type Json = z.infer<typeof jsonMapper.encoderSchema>;
// type Json = {
//   id: string;
//   age: string;
//   createdAt: string;
//   arrayDate: string[];
//   arrayNumber: string[];
//   testUnion: string;
// }

const jsonData: Json = {
  age: "1",
  id: "1",
  createdAt: "2024-12-31T10:51:52.587Z",
  arrayDate: ["2024-12-31T10:51:52.587Z"],
  arrayNumber: ["1", "2", "3"],
  testUnion: "1",
};

console.log(jsonMapper.encode(data));
//   {
//     id: '1',
//     age: '1',
//     createdAt: '2024-12-31T10:51:52.587Z',
//     arrayDate: [ '2024-12-31T10:51:52.587Z' ],
//     arrayNumber: [ '1', '2', '3' ],
//     testUnion: '1'
//   }
console.log(jsonMapper.decode(jsonData));
//   {
//     id: '1',
//     age: 1,
//     createdAt: 2024-12-31T10:51:52.587Z,
//     arrayDate: [ 2024-12-31T10:51:52.587Z ],
//     arrayNumber: [ 1, 2, 3 ],
//     testUnion: 1
//   }

custom and instanceof

  • z.custom
  • z.instanceof

Since z.custom & z.instanceOf just combined ZodAny with superRefine,doesnt have existed ZodType class. I have no way to indetify their schema in runtime.:(

ok,appearent there is workaround. But can only indetify schema base on instance instead of runtime class type or more general way. check example

z.instanceof can replaced with instanceOfClass(ZodInstaceOfClass) class come with package provide some helper functions.
instanceOfClass support private constructor.

example with ZodInstaceOfClass

export class Test {
  name: string | undefined;
  constructor(name: string) {
    this.name = name;
  }
}

export const dataSchema = z.object({
//   value: z.instanceof(Test),
  value: instanceOfClass(Test),
});

export type Data = z.infer<typeof dataSchema>;
// type Data = {
//   value: Test;
// }

export const data: Data = {
  value: new Test("hello world"),
};

const jsonMapper = createMapper(
  dataSchema,
  (schema) => ZodInstaceOfClass.isSchema(Test, schema),
  (schema) => schema.transform((value) => value.name),
  (schema) =>
    z
      .string()
      .transform((value) => new Test(value))
      .pipe(schema)
).mapper();

type Json = z.infer<typeof jsonMapper.encoderSchema>;
// type Json = {
//   value: string | undefined;
// }

const jsonData: Json = {
  value: "hello world",
};

console.log(jsonMapper.encode(data));
// { value: 'hello world' }
console.log(jsonMapper.decode(jsonData));
// { value: Test { name: 'hello world' } }

example with zod schema

const testSchema = z.instanceof(Test);

export const dataSchema = z.object({
  //   value: z.instanceof(Test),
  value: testSchema,
});

export type Data = z.infer<typeof dataSchema>;
// type Data = {
//   value: Test;
// }

export const data: Data = {
  value: new Test("hello world"),
};

const jsonMapper = createMapper(
  dataSchema,
  (schema) => isSchema(testSchema, schema), // type prediction helper method come with package
  (schema) => schema.transform((value) => value.name),
  (schema) =>
    z
      .string()
      .transform((value) => new Test(value))
      .pipe(schema)
).mapper();

Support Type

  • ZodString

  • ZodNumber

  • ZodNaN

  • ZodBigInt

  • ZodBoolean

  • ZodDate

  • ZodLiteral

  • ZodNull

  • ZodEnum

  • ZodNativeEnum

  • ZodUndefined

  • ZodVoid

  • ZodObject

  • ZodArray

  • ZodUnion

  • ZodNullable

  • ZodOptional

WIP

  • ZodLazy
  • ZodPromise
  • ZodFunction
  • ZodMap
  • ZodSet
  • ZodRecord
  • ZodNever
  • ZodTuple

About

schema mapper for zod

Resources

License

Stars

Watchers

Forks

Packages