Mapping the properties of a Zod Discriminated Union: A step-by-step guide

Suppose we have a discriminated union

export const duParser = z.discriminatedUnion('type', [
  z.object({
    type: z.literal('a'),
    id: aParser,
  }),
  z.object({
    type: z.literal('b'),
    id: bParser,
  }),
]);

The inferred result using z.infer would look like

{type: 'a', id: A} | {type: 'b', id: B}

Now, the goal is to obtain a parser and create a specific type from it, for example:

  1. Rename the union field (type) to another name (e.g. type -> type2):

    {type2: 'a', id: A} | {type2: 'b', id: B}

  2. Map other fields (although I acknowledge this can be more complex):

    {type: 'a', id2: A} | {type: 'b', id2: B}

The scenario involves having a generic parser that outputs {type: ..., id: ...}, which needs to be combined with a flat structure parser, resulting in prefixed fields for the discriminated union. The requirement for the flat parser stems from the fact that the parsed data represents an HTTP query string:

rootField1=value1&rootField2=value2&subfieldId=subValue1&subfieldType=a
where subfieldId and subfieldType correspond to the "id" and "type" attributes of the original discriminatedUnion. However, retaining them as "id" and "type" is not ideal as these attributes are part of a different abstraction level (the root entity may have its own id and type).

Typically, a nested structure would be utilized in this case, but there's curiosity about whether Zod allows for flattening and mapping field names simultaneously.

Answer №1

If I comprehend the question accurately, it seems that both tasks you are attempting to accomplish can be achieved using the transform function.

However, you may need to define the discriminated union type into which you intend to transform.

// Placeholder types for a and b parsers: number and string

interface IMappedA {
  type2: 'a',
  id2: number;
}

interface IMappedB {
  type2: 'b',
  id2: string;
}

type Mapped = IMappedA | IMappedB;

By utilizing this type, you can execute a transformation into this new discriminated union as follows:

const mappedUnionSchema = z.discriminatedUnion('type', [
  z.object({
    type: z.literal('a'),
    id: z.number(),
  }),
  z.object({
    type: z.literal('b'),
    id: z.string(),
  }),
]).transform((input): Mapped => {
  if (input.type === 'a') {
    return { type2: 'a', id2: input.id };
  } else {
    return { type2: 'b', id2: input.id };
  }
});

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

ERROR: Unhandled promise rejection: Unable to find a matching route for URL Segment 'main/knowledge-base'

After setting up dynamic routing for my Angular 6 application, I encountered an error when clicking on a link (for example, 'knowledge base') that stated: core.js:1673 ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segme ...

Strategies for increasing the number of images in Angular

At the start, 15 images are displayed from the API. However, the "Get dogs" button should load an additional 15 images each time it's clicked, but currently, it doesn't work. How can we fix this issue? http.service.ts - a service that interacts ...

The outcome from using Array.reduce may not always match the expected result

After discovering an unexpected behavior in Typescript's type-inference, I suspect there may be a bug. Imagine having a list of the MyItem interface. interface MyItem { id?: string; value: string; } const myItemList: MyItem[] = []; It's ...

Currently, I am collaborating on an e-commerce endeavor utilizing TypeScript and sanity.io, encountering an issue along the way

Encountering an Uncaught TypeError message: Cannot read properties of undefined (reading '_ref'). While attempting to utilize code for displaying API content on a webpage, what might be causing this issue and how can it be resolved to successful ...

TypeScript's attempt to replicate Scala's underscore feature has been implemented, but it proves to

I've been working on a personal project for the past 2 years trying to implement Scala's underscore in TypeScript, but haven't been successful. Here is my attempted implementation and its effect. The only thing that I really care about typi ...

The 'Element[]' type is lacking certain properties when dealing with react children

In my code, there is a parent component passing down its children to a child component. These children can be either single nodes or arrays of nodes, and the ChildComponent renders them differently based on their type. However, when I try to render the Chi ...

Enhancing Angular input validators with updates

Working on a project with Angular 6, I have set up an input field using mat-input from the Angular Material framework and assigned it an id for FormGroup validation. However, when I initialize my TypeScript class and update the input value, the validator d ...

Ways to prevent the use of the JavaScript increment (++) or decrement (--)

I have created two functions for a multi-step configuration on a webpage. protected clickNext(event:any, config:any) : any{ this.activeIndex++; } protected clickPrev(event:any, config:any) : any{ this.activeIndex--; } Here are the buttons: < ...

Challenges Faced with Implementing Active Reports in Angular 9

After following all the necessary steps outlined in this website to integrate Active Reports with Angular 9 (), I encountered an error when trying to compile my app: ERROR in The target entry-point "@grapecity/activereports-angular" has missing dependen ...

Looking to seamlessly integrate a CommonJS library into your ES Module project while maintaining TypeScript compatibility?

I am interested in creating a project with Typescript. The project is built on top of the Typescript compiler, so I am utilizing Typescript as a library, which I believe is a CommonJS library. Although the project is designed to run on Node (not in the bro ...

Troubleshooting the lack of success in enhancing global scope within Typescript

Currently, I am working on a microservices application where I have two very similar services that use practically the same packages. To perform some testing, I decided to add a function to the global scope and modified it slightly to prevent any TypeScrip ...

React-router-dom TypeScript error when defining the type of the prop parameter in the loader

I'm having trouble with the params prop in the loader prop within the routes. I've defined the params in TypeScript, but I'm getting errors that I don't understand. Any help would be appreciated, thanks in advance. I tried to use the Cu ...

Using array.map() method in React to assign unique keys to sub-children

In my latest project, I created a React component that pulls data from an Azure Cosmos database in the form of a JSON object and presents it in a card layout on a web application. The JSON structure includes multiple key/value pairs at the top level, foll ...

The element of type 'OverridableComponent<LinkTypeMap<{}, "a">>' cannot be assigned to a 'ReactNode'

I'm currently working on a project where there's a component named ListItemTextStyle. Within that component, the prop type is defined as follows: import { LinkProps, ListItemButtonProps, } from '@mui/material'; type IProps = LinkP ...

Assigning enum type variable using string in TypeScript

How can I dynamically assign a value to a TypeScript enum variable? Given: enum options { 'one' = 'one', 'two' = 'two', 'three' = 'three'} let selected = options.one I want to set the variable " ...

Determine the date and time based on the number of days passed

Hey there! I have a dataset structured like this: let events = { "KOTH Airship": ["EVERY 19:00"], "KOTH Castle": ["EVERY 20:00"], Totem: ["EVERY 17:00", "EVERY 23:00"], Jum ...

What is the proper way to define the Typescript type of the return value from the dispatch function in a Redux application?

fetchSomething is defined as follows: export const fetchSomething = createAsyncThunk( 'something', async () => { return Promise.resolve({name: 'jack'}) } ) This is the code within a React component: const dispatch = useApp ...

Typescript combined with MongoDB models

One common issue I have encountered involves a method used on my repository: async findByEmail(email: string): Promise<User | null> { const user = await UserModel.findOne({ email }); if(!user) return null; ...

"X is not compatible with these types of property," but it is not the case

I attempted to instantiate an interface object with properties initialized from another object as follows: id: data.reference.id Even though the properties are compatible, the TypeScript compiler is throwing an error. I am confused about why this is happ ...

Master the art of properly switching on reducer-style payloads in Typescript

Currently, I am dealing with two types of data: GenArtWorkerMsg and VehicleWorkerMsg. Despite having a unique type property on the payload, my Searcher is unable to differentiate between these data-sets when passed in. How can I make it understand and dis ...