Ways to adjust the properties within a type that are nested

I'm looking to modify a specific type in my code while retaining the other properties. Can anyone help?

type Foo = {
  a: {
    b: {
      c: string[]
      ...rest
    }
    ...rest
  }
  ...rest
}

Is there a way to change the type of a.b.c without affecting the other properties?

Answer №1

If you're looking to achieve something similar in TypeScript, you won't find a built-in solution. You'll need to create your own implementation using mapped types and conditional types. It's crucial to carefully consider the specific behavior you desire as there are various potential edge cases to handle, especially with optional, readonly properties, arrays, and functions.

Here is one approach you can take:

type _Overwrite<T, U> = U extends object ? (
    { [K in keyof T]: K extends keyof U ? _Overwrite<T[K], U[K]> : T[K] } & U
) : U

type ExpandRecursively<T> = T extends Function ? T : T extends object
    ? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
    : T;

type Overwrite<T, U> = ExpandRecursively<_Overwrite<T, U>>

The type _Overwrite<T, U> takes two types, T and U, recursively traverses through their properties, replacing matching ones from T with those from U when conflicts arise. While this type should suffice, be aware that it utilizes intersection types, which may lead to complexity.

Therefore, ExpandRecursively<T> merges all properties within the resulting type, ensuring that {a: string} & {b: number} becomes {a: string, b: number}.

In turn, Overwrite<T, U> applies ExpandRecursively<> on the outcome of _Overwrite<T, U>.


Let's examine how this behaves with an example:

type Foo = {
    a: {
        b: {
            c: string[];
            d: number;
        }
        e: {
            f: boolean;
        }
    };
    g: {
        h?: () => string;
    }
}

type ReplaceFoo = Overwrite<Foo, { a: { b: { c: number } } }>;

This results in:

/*
type ReplaceFoo = {
    a: {
        b: {
            c: number;
            d: number;
        };
        e: {
            f: boolean;
        };
    };
    g: {
        h?: (() => string) | undefined;
    };
}
*/

The output seems reasonable, but thorough testing is recommended before implementation. Consider scenarios where T or U might be union types, arrays, or tuples. Reflect on whether you want to differentiate between "replace a.b.c with number" and "replace a.b with {c: number}".(Do you wish to "erase" or "overwrite" subproperties?) All these considerations will influence how you implement Overwrite<T, U>.

This guidance should provide clarity on moving forward. Best of luck!

Playground Link to code

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

I'm curious about the type I can set for the first parameter of setState in TypeScript. Is there a way to pass a dynamically generated state object to setState?

When trying to pass a newState object to setState and add some additional properties under certain conditions, I encountered a type error: I attempted to define the new State as Pick<ItemListState, keyof ItemListState> but received a type error ...

Cannot proceed with module import: Type 'ModuleWithProviders<T>' must have a single type argument

ERROR in node_modules/@angular/fire/firestore/firestore.module.d.ts:7:74 - error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s). 7 static enablePersistence(persistenceSettings?: PersistenceSettings): ...

Component coding in Angular 2 allows for seamless integration and customization of Material

I am looking to initiate the start.toggle() function (associated with Angular 2 material md-sidenav-layout component) when the test() method is triggered. How can I execute md-sidenav-layout's start.toggle() in the app.component.ts file? app.componen ...

Optimal strategies for managing subscriptions in Angular

I'm currently pondering about the concept of angular subscription and unsubscription. The amount of information available on this topic is overwhelming, making it hard for me to navigate through. When is the right time to unsubscribe from a subscript ...

When someone visits a site using Next.js, the redirect feature may successfully load the site, but it fails to actually

I have a serverless logout function in Next.js: import magic from './magic'; import { withSessionRoute } from './sessions'; export default withSessionRoute(async function logoutHandler( request, response, ) { try { if (reques ...

When executing the release command in Ionic 3, the Angular AoT build encountered a failure

Struggling to get my Sony Z2 smartphone app running. Command used: ionic build android --prod --release Error displayed in console: typescript error Type CirckelmovementPage in C:/Users/fearcoder/Documents/natuurkundeformules/src/pages/cir ...

How can type annotations be properly incorporated into this TypeScript code using an inline function class?

How can I provide type annotations to inform TypeScript that this code is correct? Indeed, I do require that inline function class. The code presented here is a simplified version of my actual problem. let x = 10; const obj = new (function() { if(--x) r ...

Using TypeScript to Manipulate SVG Polyline Shapes

In my TypeScript 3.1.1 project in VS Code with an Aurelia setup, I am facing a challenge while trying to manipulate an SVG Polyline using TypeScript code. The issue arises when attempting to create a new SVGPoint object. The initial HTML structure is as fo ...

Definition file for Typescript Angular 1.5 component

Encountering a problem with typescript and angular 1.5 - when building, an error pops up saying error TS2339: Property 'component' does not exist on type 'IModule'.. Could it be that I overlooked a definition file containing this proper ...

Contrast: Colon vs. Not Equal Sign (Typescript)

Introduction Hello everyone, I am new to Typescript and currently grappling with some fundamental concepts. When defining a parameter for a function, I typically specify the type like this: function example(test: string){...} However, as I delve deeper ...

Ensuring accurate properties are sent to popup notifications

As a newcomer to a React & ASP.NET project, I am facing a challenge in displaying upload status notifications. The task may seem simple, but I need help in figuring out how to create popup notifications that indicate which files have been successfully uplo ...

Unusual Interactions between Angular and X3D Technologies

There is an unusual behavior in the x3d element inserted into an Angular (version 4) component that I have observed. The structure of my Angular project is as follows: x3d_and_angular/ app/ home/ home.component.css hom ...

Exploring the methods for monitoring multiple UDP ports on a single address in Node.js within a single process

I am currently working on developing a Node.js application to manage a small drone. The SDK provides the following instructions: To establish a connection between the Tello and a PC, Mac, or mobile device, use Wi-Fi. Sending Commands & Receiving Responses ...

Issue: Unable to load the file named 'script.ts' while employing chrome.scripting.executeScript

Currently, I am working on developing a chrome extension using Vite with React and Typescript along with CRXJS. This is my initial project in this domain. The issue I am encountering is related to executing a script on the current tab when a button is clic ...

Issue with linear Graham scan method causing failure when computing convex hull of basic polygon

It is said that the Graham scan algorithm can efficiently find the convex hull of a simple polygon in linear time without requiring the nlogn sorting step since the vertices are already effectively sorted. I have implemented the Graham scan algorithm, and ...

Steps for inserting a script tag in an Angular component

My Angular/Typescript website needs to integrate a third-party script that generates a table. However, I'm facing issues with rendering the table within the home.component.html file. I've managed to embed the script, but it doesn't seem to ...

Storing basic input values for a function

I am currently working on developing a versatile method that is capable of accepting any number of parameters, while storing the input type for future use. Let's take a look at an example: const customizedFunction = <A extends any[]>(innerFunct ...

Using TypeScript with Vue: Safely accessing component properties in a type-safe manner

I am currently exploring Vue's setup API and there is one aspect that I am struggling with: I need to retrieve properties of a child component from a parent component. Everything seems to be functioning correctly, but I am facing difficulties with the ...

Retrieving properties of a universal function

I am facing a challenge in creating a class that accepts a factory function as one of its parameters in the constructor, which is then used to create instances of another class. The implementation below is written in JavaScript. // item to create class Ite ...

Leverage TypeScript to generate a unified object that combines keys from multiple objects

Consider the object below: const myObject = { one: { fixed: { a: 1 } }, two: { fixed: { b: true } }, three: { fixed: { c: 'foo' } } } Is there a way to use this object to define a type simila ...