Exchange a TypeScript data type with a different one within an object

I am currently working with the following type definitions:

type Target = number | undefined;

type MyObject = {
    some: string;
    properties: string;
    id: Target;
}

I am trying to find a generic solution to replace instances of Target with number, for example:

type MyObjectTransformed = TargetToNumber<MyObject>;

/**
 * MyObjectTransformed is now:
 * 
 * {
 *     some: string;
 *     properties: string;
 *     id: number;
 * }
 */

It's straightforward when Target is always in the id field, but what if Target could appear anywhere? I need it to work like this too:

TargetToNumber<{
    some: string;
    other: Target;
    properties: string;
}>

And to make things more challenging, it should also handle nested occurrences. For instance, replacing Target with number in this scenario:

TargetToNumber<{
    some: string;
    properties: string;
    nested: {
        arbitrarily: {
            deep: Target;
        };
    };
}>

If you're wondering why I have such an unusual request, you can find more information here.

Answer №1

When utilizing a conditional type: in the scenario where the arbitrary type T is either A or a subtype of A, we would substitute it with B. Conversely, if the type is an object type, we recursively map its properties; otherwise, we retain the type as T.

type TargetToNumber<T> = SubstituteType<T, Target, number>;

type SubstituteType<T, A, B> =
    T extends A
    ? B
    : T extends {}
    ? { [K in keyof T]: SubstituteType<T[K], A, B> }
    : T;

If the intent is to solely substitute exactly A and maintain subtypes of A untouched (e.g. never always being a subtype...), one can swap C extends A with [A, C] extends [C, A] to verify that they are identical types.

Playground Link

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 best way to bypass TS1192 when incorporating @types/cleave.js into my Angular application?

Using cleave.js (^1.5.2) in my Angular 6 application, along with the @types/cleave.js package (^1.4.0), I encountered a strange issue. When I run ng build to compile the application, it fails and shows the following errors: ERROR in src/app/app.component. ...

Tips for importing a non-namespaced module TypeScript definition into my custom types

When working with my custom types, I want to utilize the GraphQLSchema from the graphql module. If I simply write: interface MyThing { schema: GraphQLSchema } It doesn't reference the actual GraphQLSchema definition from the module (it's just ...

Wrapper around union function in TypeScript with generics

I'm struggling to find a solution for typing a wrapper function. My goal is to enhance a form control's onChange callback by adding a console.log. Can someone please point out what I might be overlooking? interface TextInput { type: 'Tex ...

Tips on dynamically passing values according to media queries

Within my product section, there is a total of approximately 300 products. To implement pagination, I have utilized the ngx-pagination plugin. The products need to be displayed based on media query specifications. For example, if the viewport size falls wi ...

Typescript throws an error indicating that the "this" object in Vue methods may be undefined, displaying error code TS2532

As a beginner in question writing, I apologize if my wording is not clear. The issue at hand: I am working on a Vue application with TypeScript. export default { methods: { setProgram: (program: Program)=>{ this.program = progra ...

Sending an array of functions to the onClick event of a button

Having difficulty with TypeScript/JavaScript Currently working with an array of functions like this private listeners: ((name: string) => void)[] = []; Successfully adding functions to the array within another function. Now looking to trigger those ...

Develop a new flow by generating string literals as types from existing types

I'm running into a situation where my code snippet works perfectly in TS, but encounters errors in flow. Is there a workaround to make it function correctly in flow as well? type field = 'me' | 'you' type fieldWithKeyword = `${fiel ...

Updating a one-to-one relationship in TypeORM with Node.js and TypeScript can be achieved by following these steps

I am working with two entities, one is called Filter and the other is Dataset. They have a one-to-one relationship. I need help in updating the Filter entity based on Dataset using Repository with promises. The code is written in a file named node.ts. Th ...

Error TS2322: Cannot assign type 'Promise<Hero | undefined>' to type 'Promise<Hero>'

I am currently studying angular4 using the angular tutorial. Here is a function to retrieve a hero from a service: @Injectable() export class HeroService { getHeroes(): Promise<Hero[]> { return new Promise(resolve => { // ...

insert information into a fixed-size array using JavaScript

I am attempting to use array.push within a for loop in my TypeScript code: var rows = [ { id: '1', category: 'Snow', value: 'Jon', cheapSource: '35', cheapPrice: '35', amazonSource ...

Steps for eliminating the chat value from an array tab in React

tabs: [ '/home', '/about', '/chat' ]; <ResponsiveNav ppearance="subtle" justified removable moreText={<Icon icon="more" />} moreProps={{ noCar ...

Mapping nested JSON to model in Angular2 - handling multiple API requests

Having trouble integrating two HTTP API Responses into my Model in Angular 2. The first API Call returns data like so: [{ "id": 410, "name": "Test customdata test", "layer": [79,94] }, { "id": 411, "name": "Test customdata test2", ...

What does ngModel look like without the use of square brackets and parenthesis?

Can you explain the usage of ngModel without brackets and parentheses in Angular? <input name="name" ngModel> I am familiar with [ngModel] for one-way binding and [(ngModel)] for two-way binding, but I am unsure what it means when ngModel ...

Blending ASP.NET Core 2.0 Razor with Angular 4 for a Dynamic Web Experience

I am currently running an application on ASP.NET Core 2.0 with the Razor Engine (.cshtml) and I am interested in integrating Angular 4 to improve data binding from AJAX calls, moving away from traditional jQuery methods. What are the necessary steps I need ...

Avoiding repetitive logic in both parent and child components in Angular 8

In my parent controller, I have common requests and I also read router params for those requests. However, for the child components, I have different requests but still need to extract the same parameters from the router - resulting in duplicate code. For ...

Learn how to efficiently transfer row data or an array object to a component within Angular by utilizing the MatDialog feature

My goal is to create a functionality where clicking on a button within a specific row opens up a matDialog box displaying all the contents of that row. Below is the HTML snippet: <tr *ngFor="let u of users"> <td data-label="ID& ...

Issue: Query is not re-executing after navigatingDescription: The query is

On my screen, I have implemented a query as follows: export const AllFriends: React.FunctionComponent = () => { const navigation = useNavigation(); const { data, error } = useGetMyProfileQuery({ onCompleted: () => { console.log('h ...

Leveraging ngOnChanges to determine the display of an overlay based on input alterations

Working with TS/Angular on a web application, I made the decision to refactor some code that handles displaying different overlays. Instead of having separate code for each overlay, I consolidated them into one "master overlay" and created a function withi ...

How to instantiate an object in Angular 4 without any parameters

Currently, I am still getting the hang of Angular 4 Framework. I encountered a problem in creating an object within a component and initializing it as a new instance of a class. Despite importing the class into the component.ts file, I keep receiving an er ...

Refreshing Form after Saving in Angular 4

After clicking the Save button, I want to reset the form (addUserForm). I created a modal with a form to input user data. This form serves for both editing existing data and creating new data, with the flag 'Create' or 'Update' differen ...