How can you create the "Property within Key of Type" structure using Zod?

My current challenge involves a Zod shape with multiple keys. I am in need of creating another shape that mirrors the same keys, but with different types. In regular Typescript, this could be achieved with:

type TypeA = {
  something1: number
  something2: number
  ...
  somethingN: number
}

type TypeB = {
  [Property in keyof TypeA]: string
}

By defining the shapes in this way, modifying TypeA automatically updates TypeB whenever keys are added or removed. Is there a method to replicate this functionality using Zod? If so, how can it be implemented?

The code snippet below does not achieve the desired outcome, as it only provides the shape for the first type:

const TypeA = z.object({
  something1: z.number(),
  something2: z.number(),
  ...
  somethingN: z.number()
)}

type TypeA = z.infer<typeof TypeA>

type TypeB = {
  [Property in keyof TypeA]: string
}
// TypeB shape is missing

I am searching for a solution within Zod that allows for iterating over keys and assigning them specific types (or perhaps shapes before being inferred). Is this functionality supported within Zod?

Answer №1

// define the list of property keys as a constant string array.
const PropertyKeyNames = ["key1", "key2", "keyN"] as const satisfies readonly string[];
type PropertyKeys = typeof PropertyKeyNames[number];

// create TypeA and TypeB using indexed properties.
type TypeA = {[Property in PropertyKeys]: number;};
type TypeB = {[Property in PropertyKeys]: string;};

// Create a zod schema instance dynamically at runtime.

/**
 * Creates a zod object with PropertyKeyNames as keys, each having a type specified by a zod object
 * @param zobject the zod object for each property, typically z.string()
 * @returns a z.object(...) function call result
 */
const build = (zobject: z.ZodTypeAny): ReturnType<typeof z.object> => {
    const shape: { [k: string]: z.ZodTypeAny } = {};
    for (const key of PropertyKeyNames) {
        shape[key] = zobject;
    }
    return z.object(shape);
};

// The resulting zod object with string type values.
const ZobjectWithString = build(z.string());

Tests :

const TestObjects = [
    {key1: "value1", key2: "value2", keyN: "value3"}, // OK
    {key1: "value1", key2: "value2", keyN: "value3", extraKey:"extra"}, // OK
    {keyN: "value3"}, // failed
    { username: "Ludwig" }, // failed
    undefined
]
let index = 0;
for(const obj of TestObjects){
    try {
        ZobjectWithString.parse(obj);
        console.log("Test " + index + " passed");
    }catch(e){
        console.log("Test " + index + " failed");
    }
    ++index;
}

Hope this helps!

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

Utilize string variables within TypeScript's enumeration feature

Can string variables be used in enums in TypeScript? Strings can be used in enum like so: enum AllDirections { TOP = 'top', BOTTOM = 'bottom', LEFT = 'left', RIGHT = 'right', } However, trying to use variab ...

The data type 'string' cannot be assigned to the data type 'Position'

Currently, I am in the process of converting React js to typescript. The component being used is a Class Component. I would like to obtain CSS settings through props and apply them to an element. How can I resolve this issue? render(){return( <span st ...

Encountering an issue with the property name despite already defining it

Encountering a property name error even though it has been defined Uncaught (in promise): TypeError: Cannot read property 'nome' of undefined export class HomePage { inscricao = "São Bernardo"; nome = "abc"; nomeInvalido; construc ...

Angular framework does not trigger the button click event

Currently, I am in the process of creating a web app and working on designing the register page. My experience with Angular is still at a beginner level. The following code snippet is from the resiger.component.ts file: /** * To create a new User ...

Querying subdocuments within an array using MongoDB's aggregation framework

Currently, I'm facing a challenge while developing a statistics dashboard for a meditation app. I'm struggling with creating a MongoDB query to fetch the most popular meditations based on user progress. The key collections involved are users and ...

Dealing with requests on an interceptor after receiving a value from an observable in RxJS and Angular: Tips and tricks

Coming from a background in AngularJS while learning Angular 5, observables are still causing some confusion for me. I'm currently working on writing an HTTP interceptor for my authentication service. However, I'm struggling to properly return t ...

Dependency mismatch in main package.json and sub package.json

Imagine you have a project structure in Typescript set up as follows: root/ api/ package.json web/ package.json ... package.json In the main package.json file located in the root directory, Typescript is installed as a dependency to make ...

Can a discriminated union be generated using mapped types in TypeScript?

Imagine you have an interface called X: type X = { red: number, blue: string } Can a union type Y be created using mapped types? If not, are there other ways to construct it at the type level? type Y = { kind: "red" payload: number } | ...

How can I integrate the jQuery Plugin Mapael with Angular 5?

While exploring various methods that tackled the issue of integrating jQuery Plugins, I decided to start with the fundamentals. To begin with, I installed the jQuery plugin: npm i jquery Next, I included the TypeScript definition: npm install -d @types ...

What is the best way to declare a global TypeScript variable in a definition file to make it accessible for import?

My issue revolves around an external JS library that contains a global parameter: function Thing() { ... } ... var thing = new Thing(); I have a TypeScript definition file named thing.d.ts with the following content: declare var thing: ThingStatic; ex ...

Is there a way to handle null return in case the data is not present?

Is there a way to handle situations where the data I pass is empty, like if(!testimonials) return null? Currently, it just shows an empty array. I'm not sure where to implement an "if-else" rule. AboutUs Page export const getServerSideProps = async ( ...

Is it true that after setting the state in the main app with React/Recoil, it cannot be reset within a component?

Upon setting the state from the loadable within the App.js file: import React from 'react'; import { useRecoilState, useSetRecoilState, useRecoilValueLoadable } from 'recoil'; import './App.css'; import { Point } from './ ...

Why is typescript-eslint flagging the error "Unsafe call of an any typed value" whenever I try to use the delete or update methods?

type TResultCategory<T> = { title: string; items: T[]; description?: string; delete(dispatch: Dispatch<{}>): void; update?(dispatch: Dispatch<{}>, products: TCartProduct[]): void; } type TResult = (TResultCategory<TResultPro ...

Error: The use of await in RequestPromise is not valid

I encountered a TSLint error stating "Invalid 'await' of a non-Promise value." in the line of code below: const response: RequestResponse = <RequestResponse>await this.apiRequest(uri); Additional code context: private apiRequest: Request ...

Maximizing Jest's potential with multiple presets in a single configuration file/setup

Currently, the project I am working on has Jest configured and testing is functioning correctly. Here is a glimpse of the existing jest.config.js file; const ignores = [...]; const coverageIgnores = [...]; module.exports = { roots: ['<rootDir&g ...

What is the syntax for declaring a boolean or object type?

Is it possible to create a variable in TypeScript that can hold either true/false or an object of booleans? I'm still learning TS and would like some input on this syntax. variableA: { a: boolean, b: boolean } | boolean I found a workaround for now, ...

The parent component is failing to pass the form values to the child form group in CVA

My Angular application (view source code on Stackblitz) is running Angular 15, and it utilizes reactive forms along with a ControlValueAccessor pattern to construct a parent form containing child form groups. However, I am encountering an issue where the d ...

Create boilerplate code easily in VS Code by using its feature that generates code automatically when creating a

Is there a way to set up VS Code so that it automatically creates Typescript/React boilerplate code when I create a new component? import * as React from "react"; export interface props {} export const MyComponent: React.FC<props> = (): J ...

Before proceeding to update in Angular 8, ensure the repository is not dirty. Commit or stash any changes that have been

Encountered an Issue The repository is not clean. Please commit or stash any changes before updating. When upgrading from version 7 to Angular 8, I faced this error. To find out more about the upgrade process, you can visit the Angular Guide for Upgra ...

"Firebase function fails to return Typescript class variable, resulting in 'undefined'

Being someone with a background in python/golang, I am now delving into ionic2. There seems to be an issue that I can't quite figure out due to my current level of knowledge in this stack. Perhaps I just need a way to reference the outer scope of this ...