Can TypeScript's Zod library be utilized to parse a class instance?

Using the Zod validation library with TypeScript has been a great experience for me so far.

I am currently exploring the best pattern to extend Zod Schema with class-like functionality, starting with a Vector3 schema like this:

const Vector3Schema = z.object({
    x: z.number(),
    y: z.number(),
    z: z.number(),
})

type Vector3 = z.infer<typeof Vector3Schema>;

Having the type associated with Zod validation is neat and clean, but now I'm thinking about adding some class-like features to the Vector3 type.

My OOP background makes me lean towards adding basic functionalities to the type in a class-like manner, such as:

let vec1 = Vector3Schema.parse({x: 1, y: 2, z: 3});
let vec2 = Vector3Schema.parse({x: 4, y: 5, z: 6});
let distance = vec1.distance(vec2);
vec1.normalize();

The challenge is how to achieve this without duplicating class definitions and validation logic. Is there a way to parse a Zod schema into a class instance or extend the parsed type with additional functionalities?

Or perhaps it's time to embrace a more functional approach:

function normalize(v: Vector3) {...}
function distance(v1: Vector3, v2: Vector3) {...}

let vec1 = Vector3Schema.parse({x: 1, y: 2, z: 3});
let vec2 = Vector3Schema.parse({x: 4, y: 5, z: 6});
let calculatedDistance = distance(vec1, vec2);
vec1 = normalize(vec1);

I'm open to hearing your thoughts and ideas on this topic.

Answer №1

It appears that the topic of extending objects in Javascript has already been discussed here: https://github.com/colinhacks/zod/issues/641

An idea proposed is to utilize a factory function for object extension, which could potentially be adapted for use with typescript. Further exploration into this approach is recommended.

Update:

After conducting some tests, I have devised a solution tailored for typescript:

  const Vector3Schema = z.object({
    x: z.number(),
    y: z.number(),
    z: z.number(),
  });

  interface Vector3 extends z.infer<typeof Vector3Schema> {
    normalize: () => void;
    distance: (v: Vector3) => number;
  }

  function parseVector3(data: unknown): Vector3 {
    return {
      ...Vector3Schema.parse(data),
      normalize: function () { /*...*/ },
      distance: function(v: Vector3) { /*...*/}
    };
  }

Now, utilizing this solution in typescript would involve:

let vec1 = parseVector3({x:1, y: 2, z: 3});
let vec2 = parseVector3({x:4, y: 5, z: 6});
let distance = vec1.distance(vec2);
vec1.normalize();

If there are any alternative or more refined solutions to the issue, please do share them.

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

What is the method in XState to trigger an event with the parameters send('EVENT_NAME', {to: 'a value from the context'})?

I want to send an event to a different spawned state machine using its ID, which I have stored as a string in a variable within the context. This state machine is neither the parent nor child. For example: context.sendTo = 'B_id' How can I use ...

What is the significance of `/// <reference types="react-scripts" />` in programming? Are there any other XML-like syntaxes that are commonly used in *.d.ts

When working with normal *.d.ts files (which are definition files for TypeScript), we typically use declare *** export interface *** However, there is also this syntax: /// <reference types="react-scripts" /> This syntax is generated by create- ...

Unique text: "Singleton React component"

A counter component has been implemented using a npm package available here. import * as React from 'react'; import { Theme, createStyles, withStyles, WithStyles } from '@material-ui/core'; import withRoot from '../../../withRoot&a ...

Issue with triggering angular function multiple times in certain conditions

Issue: Experiencing difficulties with Angular directive as it is being called multiple times, resulting in incorrect transaction outcomes and multiple entries on the Console screen. Desired Outcome: Ensure that the function executes only once. Sample cod ...

``Is it possible to iterate through a collection of objects using a loop?

I am facing an issue with updating a global array that contains objects, where each object includes another array. My goal is to update the main array with values from the arrays within the objects following a specific logic! generalArray = [{name:String, ...

Implementing an All-Routes-Except-One CanActivate guard in Angular2

In order to group routes within a module, I am aware that it can be done like this: canActivate: [AuthGuard], children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, ...

Vue: Storing selected list values in an array

I am working on a Vue application where I need to select two elements from a list component and place them inside an array. Currently, I have my list set up with selection functionality thanks to Vuetify. I have bound the selected items to an array using v ...

Seeking guidance on transforming a thunk-based create store into a promise-based one. Any suggestions?

I am currently transitioning my app from loading data from local storage to using Firebase. Firebase always returns a promise, so I need to adapt my existing store to work with the new Firebase data. Here is the original code snippet: export const loadSta ...

Why does the Angular page not load on the first visit, but loads successfully on subsequent visits and opens without any issues?

I am currently in the process of converting a template to Angular that utilizes HTML, CSS, Bootstrap, JavaScript, and other similar technologies. Within the template, there is a loader function with a GIF animation embedded within it. Interestingly, upon ...

Tips on utilizing boolean assignment in a ternary operator with an optional property that is an array in TypeScript

I'm trying to determine the value of an object property based on whether an optional prop is an array. Here's the scenario: const requestingMultipleDevices = Array.isArray(deviceIds); Then I have this object structure: { data: requestingM ...

Issue encountered in NestJS/TypeORM: Unable to modify the property metadata of #<Repository> as it only has a getter method

When attempting to launch my nestjstutorial app, I encountered the following error message. The backend is connected to a PostgreSQL database. TypeError: Cannot set property metadata of # which has only a getter at EntityManager.getCustomRepository (D:&b ...

Implement a nested feature within the Accordion component

I am currently working on a project using Next.js and TypeScript. Within this project, I have implemented an accordion component as shown below: import React, { useEffect, useState } from 'react'; import classes from './Accordion.module.scss ...

Saving any type of file in SQL Server with a field type of varbinary(max) can be achieved by utilizing Angular with ASP.NET Core to create a REST API

I am currently facing an issue while attempting to save a file, such as an image, in the Microsoft SQL Server Management Studio through asp .NET core for the Rest API. I have managed to create a base64 representation of the file, but I am unsure about the ...

Typescript is missing Zod and tRPC types throughout all projects in the monorepo, leading to the use of 'any'

Recently, I've found myself stuck in a puzzling predicament. For the last couple of weeks, I've been trying to troubleshoot why the types are getting lost within my projects housed in a monorepo. Even though my backend exposes the necessary types ...

After calling sequelize.addModels, a Typescript simple application abruptly halts without providing any error messages

My experience with Typescript is relatively new, and I am completely unfamiliar with Sequelize. Currently, I have only made changes to the postgres config in the .config/config file to add the dev db configuration: export const config = { "dev" ...

What is the reason behind TypeScript indicating that `'string' cannot be assigned to the type 'RequestMode'`?

I'm attempting to utilize the Fetch API in TypeScript, but I keep encountering an issue The error message reads: Type 'string' is not assignable to type 'RequestMode'. Below is the code snippet causing the problem export class ...

Call a function within a stateless component in a React application

I have a question regarding my React component. I am attempting to call the function ButtonAppBar within my stateless component, but the TypeScript compiler is throwing an error stating '{' expected. I'm unsure whether I need to pass it to m ...

Can InstanceType<T> be utilized with an abstract class?

My intention is to enable it to reference implementations rather than the abstract itself, all while exclusively depending on the definitions in the abstract interface. ...

What is the process for creating a new Object based on an interface in Typescript?

I am dealing with an interface that looks like this: interface Response { items: { productId: string; productName: string; price: number; }[] } interface APIResponse { items: { productId: string; produc ...

Retrieving data from a JSON using Typescript and Angular 2

Here is an example of what my JSON data structure looks like: { "reportSections": [ { "name": "...", "display": true, "nav": false, "reportGroups": { "reports": [ { "name": "...", "ur ...