Ways to elegantly replace an object with thorough validation of its embedded properties

Consider the following code snippet:

interface Human{
  name:string
  age:number
  dimensions : {
    height:number
    width:number
  }
}

const base : Human ={
  name:"Base",
  age:12,
  dimensions : {
    height:190,
    width:99
  }
};


const child : Human = lodashMerge(base,{
  age:22,
  dimentions:{
     height:99
  }
}) // This operation should be successful


const child2 : Human = lodashMerge(base,{
  hairColor:'red'
}) // This operation should throw an error due to the property 'hairColor' not existing in the base object

Answer №1

Assuming that lodashMerge refers to lodash's _.merge method, you will encounter limitations if you solely rely on this method. To address this issue while maintaining the functionality of the method, it is necessary to encapsulate it within a custom function where a more specific type definition can be implemented. The current definition provided by lodash is overly lenient for your requirements.

The detailed type definition for this method can be accessed here. Upon examination, it reveals that each overload's return type is an intersection of its arguments, whereas you seek the exact type of the initial argument as the return type.

To resolve this, I recommend creating a wrapper function with a desired signature. Here is a potential implementation:

// Utilizing only the final overload (variadic) for future reference.
declare function lodashMerge(object: any, ...otherArgs: any[]): any;

type DeepPartial<T> = {
    [K in keyof T]?: DeepPartial<T[K]>;
}

function myMerge<T>(base: T, ...args: DeepPartial<T>[]): T {
    return lodashMerge(base, ...args);
};

By employing this approach, errors will be flagged in your second example but not the first. (Note: In both examples, an error occurs due to the misspelling of "dimensions".)

// No issues, functions correctly.
const child : Human = myMerge(base,{
  age:22,
  dimensions:{ // Corrected spelling; without correction, error would occur.
     height:99
  }
})

// Error: Refer to explanation below
const child2 : Human = myMerge(base,{
  hairColor:'red' // Error: Object literal may only specify known properties, and 'hairColor' does not exist in type 'DeepPartial<Human>'.
})

Answer №2

The code snippet provided does not include the crucial part that determines whether an error will be detected. The outcome relies heavily on how lodashMerge has been implemented.

If you intend to pass incomplete objects, it might be worth considering using Partial<Human> as the parameter type for the lodashMerge function. Alternatively, you can utilize { age: 99 } as any to bypass the strict type checks altogether.

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

Creating a new component when a click event occurs in React

Currently diving into the world of React while working on a project that involves mapbox-gl. I'm facing an issue where I can successfully log the coordinates and description to the console upon hover, but I can't seem to get the popup to display ...

What is the process for attaching a function to an object?

Here is the complete code: export interface IButton { click: Function; settings?: IButtonSettings; } abstract class Button implements IButton { click() {} } class ButtonReset extends Button { super() } The component looks like this: expor ...

Generate a binary string using JavaScript and then transform it into C#

I have an upload section in my JavaScript program. I utilize JS FileReader to obtain a binary string of the uploaded document before sending it to my C# WebApi for storage on the server. JavaScript Code let myFile = ev.target.files[0]; if(myFile.size > ...

What is the reason behind continuously receiving the error message stating "Not all code paths return a value here"?

Can someone help me understand why I am consistently encountering this error message from typescript? PS. I am aware that in this scenario I could simply use a boolean and not create a function, but my focus here is on typescript. I keep receiving the er ...

"Unlocking the full potential of Typescript and Redux: Streamlining the use of 'connect' without the need to

I am facing some challenges with typescript and redux-thunk actions. The issue arises when my components heavily rely on react-redux connect to bind action creators. The problem occurs when I create the interface for these redux actions within the compone ...

Presentation of information with loading and error scenarios

How can we effectively display data in an Angular view, considering loading state and error handling? Imagine we are fetching a set of documents from our backend and need to present them in an Angular view. We want to address three possible scenarios by p ...

What is the proper type for an object and an array of strings?

We have an array example below. const sampleArray = [ {names: ['example1', 'example2']}, 'another', 'final' ]; Additionally, here is a type error example. The error message reads as follows: "Type 'string ...

An error is triggered when an HttpClient post does not return any data

While sending a post request from my angular application to a web api, I am encountering an issue. The response from the api is supposed to be either a 200 status or a 404 status without any data being returned. An example of some headers for the 200 respo ...

What is the best way to retrieve entire (selected) objects from a multiselect feature in Angular?

I'm facing an issue with extracting entire objects from a multiselect dropdown that I have included in my angular template. Although I am able to successfully retrieve IDs, I am struggling to fetch the complete object. Instead, in the console, it dis ...

The specified type 'undefined' cannot be assigned to the type '"default" | "red" | "green" | "blue"

I am currently developing an app using React and TypeScript. Can someone help me troubleshoot and resolve the error message below? import { styled } from "linaria/react"; type Color = { color: "default" | "red" | "gree ...

Discovering the Object with the Lowest Key Value in Typescript

Within my TypeScript code, I have defined a List as myList: Package[]. The structure of the Package model is outlined below - export class Package { ID: Number; Price: Number; } I am trying to retrieve a Package object with the lowest Price value using ...

Exploring the various form types supported by 'react-hook-form'

I utilized react hooks form to create this form: import React from "react"; import ReactDOM from "react-dom"; import { useForm, SubmitHandler } from "react-hook-form"; import "./styles.css"; function App() { type ...

Zod implements asynchronous validation for minimum, maximum, and length constraints

When working with Zod, setting values can be done as shown below: z.string().max(5); z.string().min(5); z.string().length(5); However, in my scenario, the values (e.g., 5) are not predetermined. They are fetched from an API dynamically. How can I create t ...

Incorporate the Get Your Guide Widget into an Angular2 component

Currently, I am attempting to embed a "Get Your Guide" Widget within an Angular2 application. Although the script in index.html is being requested successfully, I am facing difficulties adding it to the HTML of the component. <script async defer src=" ...

Tips on maintaining the chosen product while navigating to a different component

I have a dilemma with 2 different components that are responsible for creating an invoice. The first component adds more products The second component adds invoice details Initially, I enter the invoice details and select the client's name. The sel ...

Typescript is failing to return nested types when attempting to return a nested object

My goal is for my function to return a nested type of Content, but it's not working even though the type that should be returned is known. Let's take a look at an example: type Content = { some: { extra: string; prop: number; ...

Employing Multer and Express in conjunction with TypeScript

Overview Currently, I am working on a project that involves creating a user-friendly website where individuals can easily upload images. For this particular task, I have employed Node.js, React, Multer, and Typescript. Issue at Hand app.post('/admi ...

The activation of [routerLinkActive] triggers an error related to the data.split function

In my lazy loaded module, I have implemented simple routing as shown below: <div id="nav"> <div class="nav-content"> <div class="nav-item" [routerLink]="'basic'" [routerLinkActive]="active-nav"> <span ...

Replacing the '+' character with a space in HttpParams within Angular 6

When passing a JSON object using HttpParams, the + character is automatically converted to a space before being sent to the backend. Despite trying multiple solutions, I have been unable to resolve this issue for a JSONObject string. this.updateUser({"nam ...

What is the correct way to utilize the createAsyncThunk function in TypeScript?

You can access the entire project here. I currently have this code snippet: extraReducers: (builder) => { builder .addCase(getTodosAsync.fulfilled, (state, action:any) => { return action.payload.todos ...