Tips on implementing zod schema types with remapped fields using the toZod method

I'm currently working on mapping a schema key to a different name in my database

interface Country {
        isoCode: string,
        nameEn: string,
        nameDe: string,
        phone: string,
        bla: string
}

const CountryJson = {
        isoCode: 'DE',
        nameEn: 'Germany',
        nameDe: 'Deutschland',
        phone: '+49',
        blubb: 'test123'
}

const testZodObj: toZod<Country> = z.object({
        isoCode: z.string(),
        nameEn: z.string(),
        nameDe: z.string(),
        phone: z.string(),
        blubb: z.string(),
}).transform((item)=>{
        const {blubb: bla, ...rest} = item
        return {
                ...rest,
                bla
        }
})

type countryArray = z.infer<typeof testZodObj>

function print(): countryArray{
        return testZodObj.parse(CountryJson)
}

const out = print()
console.log(out)

However, the transform function returns a ZodType, causing testZodObj to now expect a ZodEffects. Do you have any suggestions on how I could make the key names match the interface?

blubb is the value retrieved from the API and bla is the value I want to store it as.

Answer №1

To simplify the problem statement somewhat, let's consider having the following types for both remote and local data:

interface ILocal {
  a: number;
}

interface IRemote {
  b: number;
}

When parsing, you anticipate the field b retrieved from the API to be placed under a new key: a. This can be easily accomplished by defining an explicit type transformation as shown below:

import { z } from 'zod';
const schema: z.ZodType<ILocal, z.ZodTypeDef, IRemote> = z.object({
  b: z.number(),
}).transform(({ b }) => ({ a: b }));

console.log(schema.parse({ b: 11 }).a); // => 11

An important aspect here is ensuring that the input type differs from the output type explicitly. While z.ZodType usually requires specifying only the output type, in cases where key remapping is needed, the third parameter should be provided.

The result of the .transform(...) operation will still yield a ZodEffect, but it will align with the explicit ZodType.

If you decide to eliminate the ILocal interface and use z.infer instead:

const schema = z.object({
  b: z.number(),
}).transform(({ b }) => ({ a: b }));
type Local = z.infer<typeof schema>;

Local will be inferred to be similar to ILocal.


Delving into opinion territory—please note this is separate from the solution provided, but could be relevant

After some additional research regarding any missing context, I encountered the toZod library which appears to be causing complications. Personally, I find it unclear why one would opt for that library when similar outcomes can be achieved using the fundamental zod library described above. By specifying

z.ZodType<ILocal, z.ZodTypeDef, IRemote>
as a clear type definition, adherence to the zod schema on the right-hand side is enforced. Any deviation in the schema output will trigger a type error without necessitating toZod.

Here's a demonstration tailored to your specific scenario:

// Define this to prevent redundancy
interface IBaseCountry {
  isoCode: string;
  nameEn: string;
  nameDe: string;
  phone: string;
}
interface Country extends IBaseCountry {
  bla: string;
}
interface RemoteCountry extends IBaseCountry {
  blubb: string;
}

const testZodObj: z.ZodType<Country, z.ZodTypeDef, RemoteCountry> = z.object({
  // Insert your code here
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The function Sync in the cp method of fs.default is not a valid function

When attempting to install TurboRepo, I encountered an issue after selecting npm. >>> TURBOREPO >>> Welcome to Turborepo! Let's get you set up with a new codebase. ? Where would you like to create your turborepo? ./my-turborepo ...

Developing a custom React hook that utilizes the useContext functions

When attempting to utilize a function within a custom hook, I encounter the following error message: Error: tglCartao is not defined The custom hook code in UseCartao.tsx is as follows: export interface ICartaoContext { idToggleKey : string; ...

The upcoming router is not compatible with the NextPage type

I am currently working on introducing dynamic routing into an application that was originally designed with static routes. However, I am facing some confusion as I encounter TypeScript errors that are difficult for me to understand. Below is the code snipp ...

What is the best way to close ngx-simple-modal in angular7 when clicking outside of the modal component?

Can anyone help me with closing the modal in my angular7 app when the user clicks outside of the modal component? I have been using the ngx-simple-modal plugin, and I tried implementing the following code: this.SimpleModalService.addModal(LinkPopupCompone ...

Automatic completion of absolute paths in VS Code with the ability to click and view definitions through the configuration file js/tsconfig.json

In order to ensure that absolute paths function correctly, I have found that there are two key steps involved: the compilation process and configuring the code editor. I successfully managed the compilation aspect by utilizing babel-plugin-module-resolver ...

Each time the Angular Service is called, it undergoes a reset process

For my Angular web project, I have implemented an AuthenticationGuard and an AuthenticationService to manage security. These components are from a separate branch of the project that is functioning perfectly. This is how the process should occur: Go to ...

Retrieve a static property from a specific type

I've encountered a dilemma with the code snippet below: class Action { public static DEPENDENCIES: (typeof Action)[] = []; public static MIN_USES: number | null = null; public static MAX_USES: number | null = null; } class SomeAction ext ...

What is the best way to define a function agreement in Typescript?

I have created a function that can return `undefined` only when its argument is also `undefined`, otherwise it will always return a value derived from the argument provided. Here's an example of how the function works: function triple(value?: number) ...

Improving the App() function in React and Typescipt

When working on my React/Typescript app, I encountered a challenge with the length of the code in one of the sections. Despite watching tutorials and searching for solutions, I couldn't find a clear way to refactor it. The specific issue is with refa ...

What is the issue with this asynchronous function?

async getListOfFiles(){ if(this.service.wd == '') { await getBasic((this.service.wd)); } else { await getBasic(('/'+this.service.wd)); } this.files = await JSON.parse(localStorage.getItem('FILENAMES')); var ...

Derive a data type from a parameter passed to a function defined within an interface

I am working with a function defined in an interface as shown below: interface UseAutocompleteReturnValue { ... getRootProps: (externalProps?: any) => React.HTMLAttributes<HTMLDivElement>; } Within my interface, I aim to create a prop named rootP ...

Compilation of various Typescript files into a single, encapsulated JavaScript bundle

After researching countless similar inquiries on this topic, I have come to the realization that most of the answers available are outdated or rely on discontinued NPM packages. Additionally, many solutions are based on packages with unresolved bug reports ...

Strange interaction observed when working with Record<string, unknown> compared to Record<string, any>

Recently, I came across this interesting function: function fn(param: Record<string, unknown>) { //... } x({ hello: "world" }); // Everything runs smoothly x(["hi"]); // Error -> Index signature for type 'string' i ...

Unable to get md-virtual-repeat to work within md-select?

Attempting to use md-select to showcase a large amount of data is causing the browser to freeze upon opening. To address this, I tried implementing md-virtual repeat within md-select for improved performance. However, the code doesn't seem to be funct ...

Encountering a 404 error while trying to deploy a React app on Verc

After deploying my React project with TypeScript using Vite, everything is working smoothly. However, I am encountering a 404 error when trying to refresh the page. Error: 404 NOT_FOUND Error Code: NOT_FOUND ...

The Angular CLI suddenly decided to stop providing me with useful lines (without sourcemaps) in the browser console, but interestingly the terminal continues

I recently noticed a change in my Angular project that is using Angular CLI. Instead of receiving error lines from my code, I am getting errors from compiled files like main.js and vendor.js. The 'normal' error messages in my terminal are pointin ...

Exploring the functionality of className using materialUI

Attempting to test whether my component has a specific class is proving challenging. This difficulty stems from the fact that the class is generated using MaterialUI. For instance, I am looking for a class named spinningIconCenter, but in reality, it appea ...

Angular2 encounters an error when processing a custom HTTP request

I offer two unique services Custom HTTP client service fetch(url):any{ this.storage.fetchData('auth-token').then((token) => { let headers = new Headers(); this.prepareHeaders(headers); return this.http.fetch(url+"?token="+toke ...

Unable to reference the namespace 'ThemeDefinition' as a valid type within Vuetify

Looking to develop a unique theme for Vuetify v3.0.0-alpha.10 and I'm working with my vuetify.ts plugin file. import "@mdi/font/css/materialdesignicons.css"; import "vuetify/lib/styles/main.sass"; import { createVuetify, ThemeDefinition } from "v ...

Adding an object with a composite key to an IndexedDB object store is not permitted as the key already exists within the store. This limitation occurs when attempting to add an entry

I am facing an issue with my objectStore where adding an object with the same productId but a different shopName triggers an error in the transaction showing: ConstraintError: Key already exists in the object store.. This is how I initialized the objectSto ...