Unlocking the potential of TypeScript magic through recursion: A comprehensive guide

There are two methods available:

public prop<K extends keyof ResponseInvitation.RootObject>(key: K) {
    return this._has(key) ? this.user[key] : null;
  }

  private _has(prop: string): boolean {
    return this.user.hasOwnProperty(prop);
  }

To use these methods, you can do the following:

let prop = this.prop('profile'); // Returns an object 

How to chain call this.prop when the returned property is an object:

 let prop = this.prop(this.prop('profile').organization);

In the scenario above, we first try to retrieve the property named profile, which returns an object containing the property organization as a string.

If I understand correctly, you require this additional logic:

private _has(prop: string): boolean {
    let prop = this.user.hasOwnProperty(prop);

    if (typeof prop == 'object') {
       return this._has(prop);
    }
}

I encountered a similar issue and managed to rewrite the logic with the following code:

interface RootObject { 
  name: string;
  organization: Org; 
}

interface Org { 
  name: string;
}

class A { 

  public user: any;
  public last: string;

public prop<K extends keyof RootObject>(key: K) {
  let  prop = this._has(key) ? this.user[key] : null;

  if (key == this.last) { 
    return prop;
  }

  if (typeof prop == 'object') {
    let k = Object.keys(prop)[0] as K;
    this.user = prop;
    return this.prop(k);
  }

  }

  private _has(prop: string): boolean {
    return this.user.hasOwnProperty(prop);
  }

  public propString(properties: string) { 
    this.last = properties.split('.').slice(-1).pop();
  }

}

let b = {
  'organization': {
    'name': 'Oleg'
  }
};

let a = new A();
a.user = b;
a.propString('organization.name');
let d = a.prop('organization');
console.log(d);

Answer №1

I'm unsure about the specifics of your request as you haven't provided all details of your class implementation. Here is a more generalized solution that may help you achieve your goal:

type WrapIfObject<T> = T extends object ? ObjectWrapper<T> : T; 
class ObjectWrapper<T> {
  constructor(public object: T) { }
  prop<K extends keyof T>(k: K): WrapIfObject<T[K]>;
  prop<K extends keyof T>(k: K): T[K] | ObjectWrapper<T[K]> {
    const val = this.object[k];
    return (typeof val === "object") ? new ObjectWrapper(val) : val;
  }
}

The code above defines a class called ObjectWrapper, which wraps an object passed into its constructor. When you use the prop() method with one of the object's keys, it will either return the property value if it's not an object, or an ObjectWrapper that wraps the property value. This allows you to chain calls to prop() until you reach a non-object value. The return type of prop(), WrapIfObject<T[K]>, is a conditional type for strong typing.

Let's see how it operates:

const val = {a: {b: "hey"}, c: "you"};
const valWrap = new ObjectWrapper(val);
console.log(valWrap.prop("a").prop("b").charAt(0)); // "h"
console.log(valWrap.prop("c").charAt(0)); // "y"

The above code type-checks without errors. TypeScript correctly infers that valWrap.prop("a").prop("b") is a string, and valWrap.prop("c") is also a string. It will raise an error if misused:

const oops = valWrap.prop("a").charAt(0); // error!
// Property 'charAt' does not exist on type 'ObjectWrapper<{ b: string; }>'.

Furthermore, due to the distributive nature of conditional types, unions are generated in appropriate instances:

const x = new ObjectWrapper({a: Math.random() < 0.5 ? "string" : {b: 3}});
const y = x.prop("a"); // string | ObjectWrapper<{b: number}>
const z = (typeof y === "string") ? y.length : y.prop("b"); // number
console.log(z); // 6 or 3

Notice how y can be either a string or an ObjectWrapper<{b: number}>.

Hopefully, this example gives you insight into resolving your issue. Good luck!

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 perform a conditional check and return a customized object while working with a Promise?

I have developed a provider specifically for handling all Firebase database related requests. In the getUser method, when the data is fetched from the database using .once which returns a promise, if the object is null it currently returns null. This means ...

Tips on utilizing array filtering in TypeScript by solely relying on index rather than element callback

When running tslint, I encountered the following error message: https://i.sstatic.net/p2W9D.png Is it possible to filter based on array index without utilizing element callback? Any alternative suggestions would be appreciated. ...

What is the best way to define this.someProperty in a React component using TypeScript?

I'm encountering an issue with TS2339: Property 'someProperty' does not exist on type ''. I am attempting to add a new property to my React component using this.someProperty. interface MyComponentState { allClear: boo ...

Google Maps not displaying in nested Angular 2 component

After following the recommended steps to place Google map code in the Angular2 app.component, everything was working perfectly. However, I encountered an issue when trying to display the map in a shared nestable component called google-maps.component. The ...

Trouble with updating data in Angular 5 through page reload

Encountered a problem with the home, create, and edit product pages. After creating and saving data, it redirects to the home page where the latest products are displayed. Unfortunately, the newly created data does not update automatically until the page ...

Working with Typescript and JSX in React for event handling

I'm currently facing an issue with updating the state in a React component I'm developing using TypeScript (React with Addons 0.13.3, Typescript 1.6.0-dev.20150804, definition file from ). /// <reference path="react/react-addons.d.ts" /> i ...

Having difficulty reaching the specified route ID in Angular app

I'm encountering an issue when attempting to navigate to a route with an ID argument using the router. Here's the code snippet from my component: import { Router } from '@angular/router'; ... constructor(private router: Router) { } .. ...

Creating a dynamic dropdown menu where the available options in one select box change based on the selection made in another

Looking at the Material-UI Stepper code, I have a requirement to create a select element with dynamic options based on the selected value in another select within the same React component. To achieve this, I wrote a switch function: function getGradeConte ...

Waiting for the execution of the loop to be completed before proceeding - Typescript (Angular)

There's a code snippet triggered on an HTML page when clicked: public salaryConfirmation() { const matDialogConfig: MatDialogConfig = _.cloneDeep(GajiIdSettings.DIALOG_CONFIG); this.warningNameList = []; for(let i=0; i < this.kelolaDat ...

What is the best way to create an Office Script autofill feature that automatically fills to the last row in Excel?

Having trouble setting up an Excel script to autofill a column only down to the final row of data, without extending further. Each table I use this script on has a different number of rows, so hardcoding the row range is not helpful. Is there a way to make ...

Project references have caused TypeScript path aliases to no longer function as expected

In the past, I encountered an issue with package.json not being placed under rootDir. Fortunately, I stumbled upon a helpful question on StackOverflow that addressed this exact problem. By following the recommendations provided in this answer, I managed to ...

Utilize interface as a field type within a mongoose Schema

I am currently working with typescript and mongoose. I have defined an interface like this: interface Task { taskid: Boolean; description: Boolean; } My goal is to create a schema where one of the fields contains an array of Tasks: const employeeSche ...

Struggling to create a functioning toggle button using jQuery in a React application

I've encountered an issue with my react web application. I'm trying to implement a voting system where clicking the like button changes its color and functionality, allowing it to be liked only once. If clicked again, it should return to a neutra ...

What steps do I need to follow to create a unique angular component that allows for customizable width using CSS styles?

The instructions on this website suggest that the width of the side-nav can be changed using CSS like so: md-sidenav { width: 200px; } This leads me to wonder, can I apply standard CSS properties such as width, position, etc... to custom components wi ...

Error: Unable to access the 'replace' property of an object that is not defined during object instantiation

Check out my class and interface below: export interface Foo{ numFoo: string } export class Blah{ constructor( public numBlah: string, public arrayOfFoos: Array<Foo>, public idBlah: string ) { } } let numBlah: string = ' ...

Discovering duplicates for properties within an array of objects in React.js and assigning a sequential number to that specific field

I am working with an array of objects where each object contains information like this: const myArr=[{name:"john",id:1}{name:"john",id:2}{name:"mary",id:3}] In the first 2 elements, the "name" property has duplicates with the value "john". How can I updat ...

Maximizing the potential of typescript generics in Reactjs functional components

I have a component within my react project that looks like this: import "./styles.css"; type InputType = "input" | "textarea"; interface ContainerProps { name: string; placeholder: string; as: InputType; } const Conta ...

Having trouble loading an image from the /public directory in a React, Next.js, TypeScript configuration

I'm encountering a 404 not found error with my image that's in the public directory when using <img src="/signature.png" /> I've spent hours trying to figure out what could be causing this issue. Does anyone have any insight ...

How to navigate to the bottom of a webpage with Angular 4 using TypeScript's onClick event

Within my component, I have a template that looks like the following. When this div is clicked, the intention is to scroll to the bottom of the page. `<section><div onclick='scrollDown()'>Goto Reports</div></section><d ...

What is the proper syntax for specifying a specific field in a generic class?

type Specific = {field: 'add'} | {field:'remove'}; function add(value: Specific) {} // Ensures value.field === 'add' function remove(value: Specific) {} // Ensures value.field === 'remove' How can I restrict functi ...