1-
2- type TextBlock = {
3- type: "text";
4- content: string;
5- format?: "bold" | "italic" | "underline";
6- };
7-
8- type ImageBlock = {
9- type: "image";
10- url: string;
11- caption?: string;
12- width?: number;
13- };
14-
15- type ListBlock = {
16- type: "list";
17- items: string[];
18- style: "bullet" | "numbered";
19- };
20
21-
22- type Block = TextBlock | ImageBlock | ListBlock;
23
24+ import { z } from "zod";
25
26+
27+ const textBlockSchema = z.object({
28+ type: z.literal("text"),
29+ content: z.string(),
30+ format: z.enum(["bold", "italic", "underline"]).optional(),
31+ });
32+
33+ const imageBlockSchema = z.object({
34+ type: z.literal("image"),
35+ url: z.string().url(),
36+ caption: z.string().optional(),
37+ width: z.number().positive().optional(),
38+ });
39+
40+ const listBlockSchema = z.object({
41+ type: z.literal("list"),
42+ items: z.array(z.string()),
43+ style: z.enum(["bullet", "numbered"]),
44+ });
45+
46+
47+ const blockSchema = z.discriminatedUnion("type", [
48+ textBlockSchema,
49+ imageBlockSchema,
50+ listBlockSchema
51+ ]);
52
53+
54+ type Block = z.infer<typeof blockSchema>;
55
56-
57- function validateBlock(input: unknown): { valid: boolean; block?: Block; error?: string } {
58- if (!input || typeof input !== "object") {
59- return { valid: false, error: "Input must be an object" };
60- }
61-
62- if (!("type" in input)) {
63- return { valid: false, error: "Missing 'type' property" };
64- }
65-
66- if (input.type === "text") {
67- if (!("content" in input) || typeof input.content !== "string") {
68- return { valid: false, error: "Text block missing content string" };
69- }
70- if (input.format && !["bold", "italic", "underline"].includes(input.format)) {
71- return { valid: false, error: "Invalid text format" };
72- }
73- return { valid: true, block: input as TextBlock };
74- }
75-
76- if (input.type === "image") {
77- if (!("url" in input) || typeof input.url !== "string") {
78- return { valid: false, error: "Image block missing url string" };
79- }
80- return { valid: true, block: input as ImageBlock };
81- }
82-
83- if (input.type === "list") {
84- return { valid: true, block: input as ListBlock };
85- }
86-
87- return { valid: false, error: "Unknown block type" };
88- }
89
90+
91+ function validateBlock(input: unknown) {
92+ return blockSchema.safeParse(input);
93+ }
94
95-
96- const block = { type: "text", content: "Hello world" };
97- const result = validateBlock(block);
98- if (result.valid && result.block) {
99- if (result.block.type === "text") {
100- console.log(result.block.content);
101- }
102- } else {
103- console.error(result.error);
104- }
105
106+
107+ const block = { type: "text", content: "Hello world" };
108+ const result = validateBlock(block);
109+ if (result.success) {
110+ if (result.data.type === "text") {
111+ console.log(result.data.content);
112+ }
113+ } else {
114+ console.error(result.error.format());
115+ }