The transform method in Zod is used to modify or reshape the output of a schema after its validation step but before it is returned to the user. This is incredibly useful when you want the input to be processed or altered before you further work with it.
Zod allows developers to define validation schemas for a wide variety of data types, but raw validation alone isn’t always enough. With transform, Zod provides a flexible way to apply additional logic to the validated values.
The syntax of the transform method is straightforward. It accepts a function that takes the parsed value (i.e., the value that passed validation) and returns a modified version of it.
const schema = z.string().transform((val) => val.toUpperCase());
In the example above, we first validate that the input is a string, and then we use the transform method to convert it to uppercase. This transformation happens after the validation has already succeeded.
One of the most common use cases is transforming strings, such as converting text to lowercase, uppercase, or trimming unnecessary whitespace.
const emailSchema = z.string().email().transform((val) => val.toLowerCase().trim()); const result = emailSchema.parse(" USER@EXAMPLE.COM "); console.log(result); // "user@example.com"
This is handy for normalizing input like email addresses. The string is first validated as a proper email and then transformed by making it lowercase and trimming any surrounding spaces.
Numbers are another frequent candidate for transformation, where you might want to format or adjust them.
const priceSchema = z.string().transform((val) => parseFloat(val)); const price = priceSchema.parse("19.99"); console.log(price); // 19.99 (as a number)
In this example, the input is a string representation of a number, but we transform it into a JavaScript number using parseFloat. This can be useful when accepting form data where everything is received as a string.
Zod also allows you to transform arrays. This is useful when you want to modify the elements inside an array or change its structure.
const numberArraySchema = z .array(z.string()) .transform((val) => val.map(Number)); const numbers = numberArraySchema.parse(["1", "2", "3"]); console.log(numbers); // [1, 2, 3] (as an array of numbers)
Here, each string inside the array is converted to a number. Zod validates that the array contains strings, then transforms them into numbers.
You can also transform entire objects by changing their structure or individual properties.
const userSchema = z .object({ firstName: z.string(), lastName: z.string(), }) .transform(({ firstName, lastName }) => ({ fullName: `${firstName} ${lastName}`, })); const user = userSchema.parse({ firstName: "John", lastName: "Doe" }); console.log(user); // { fullName: "John Doe" }
In this case, we take an object with firstName and lastName and transform it into a new object that only contains a fullName property. This demonstrates how transform can restructure data entirely.
Zod supports asynchronous transformations as well. This can be particularly useful when you need to fetch additional data or perform asynchronous operations during transformation.
const asyncSchema = z .string() .transform(async (val) => { // Simulate an async operation, e.g., calling an API const result = await fakeApiCall(val); return result; }); async function example() { const result = await asyncSchema.parseAsync("input"); console.log(result); } example();
In this example, we simulate an asynchronous API call that modifies the string input. Remember to use parseAsync instead of parse when dealing with async transforms.
You can chain multiple transform calls to apply successive transformations to the data.
const schema = z .string() .transform((val) => val.trim()) .transform((val) => val.toLowerCase()); const result = schema.parse(" HeLLo WoRLd "); console.log(result); // "hello world"
Here, the input string is first trimmed and then converted to lowercase. Each transform operates on the result of the previous one, providing a step-by-step pipeline for processing data.
While zod.transform is a powerful tool, you need to be mindful of how errors are handled within your transform functions. If the transformation fails, you need to handle it properly or let Zod report the error.
const schema = z.string().transform((val) => { if (val === "") throw new Error("Cannot transform an empty string."); return val.toUpperCase(); }); try { schema.parse(""); } catch (e) { console.error(e); // "Cannot transform an empty string." }
In this case, an empty string triggers a custom error. Zod will propagate this error, allowing you to catch and handle it accordingly.
When working with async transforms, forgetting to use parseAsync can cause your code to break.
const asyncSchema = z.string().transform(async (val) => await someAsyncOperation(val)); // This will throw an error because the transformation is asynchronous const result = asyncSchema.parse("input"); // Use parseAsync instead
Not handling errors inside the transformation function can lead to unhandled promise rejections or incorrect data being returned.
The zod.transform method is an essential part of Zod's functionality, allowing developers to modify validated data efficiently. By following the practices and use cases outlined above, you can make the most of this powerful feature in your applications.
simplify and inspire technology
©2024, basicutils.com