`The enforcement of a function's parameter requiring it to be part of the generic type T`

Is there a way in my typescript function to ensure that all keys in the second argument belong to the object defined by the first argument?

For example:

mapTo([new KeyValue('a', 'b'), new KeyValue('x', 'y')], {key: {key2: 1}});

In this scenario, all keys in the second argument (key and key2) must match the keys defined in the KeyValue object.

Here is the definition of the KeyValue class:

class KeyValue {
  key: string;
  key2: string;

  constructor(k, k2) {
    this.key = k;
    this.key2 = k2;
  }
}

Like so:

mapTo([new KeyValue('a', 'b')], {key: {key2: 1}}); -> valid

mapTo([new KeyValue('a', 'b')], {key: {key3: 1}}); -> invalid // key3 does not exist

To achieve this, I have implemented the mapTo function as follows:

public nest<T, K extends keyof T, K2 extends keyof T>(arr: [T], basis: {[k in K]: {[k2 in K2]}}) {
    console.log('Hello!!!');
    console.log(basis);
  }

The code works perfectly, but if I add another key to the KeyValue class and use it in the arguments like this:

mapTo([new KeyValue('a', 'b' ,'c')], {key: {key2: {key3: 1}}});

And update the KeyValue class definition:

class KeyValue {
  key: string;
  key2: string;
  key3: string;

  constructor(k, k2, k3) {
    this.key = k;
    this.key2 = k2; 
    this.key3 = k3;
  }
}

Then, the previously implemented function will not validate the third key. How can I adjust the function to accept dynamically nested values and still work perfectly?

Additional examples:

mapTo([new KeyValue('a', 'b' ,'c')], {key: 1}); -> valid

mapTo([new KeyValue('a', 'b' ,'c')], {key: {key1:1}}); -> valid

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:1}}); -> valid

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key3:1}}}); -> valid

mapTo([new KeyValue('a', 'b' ,'c')], {key1: {key:{key4:1}}}); -> invalid // key4 does not exist

mapTo([new KeyValue('a', 'b' ,'c')], {key3: {key2:0}}); -> valid

Answer №1

To create a versatile structure that allows any key of type T to be specified at each level without repetition, you can utilize a recursive mapped type along with the Omit type. This approach ensures that no key is specified twice in a given path:

type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;

type Nested<T> = { [P in keyof T]?: Nested<Omit<T, P>> | number }

function mapTo<T>(arr: [T], basis: Nested<T>) {
    console.log('Hello!!!');
    console.log(basis);
}

class KeyValue {
    constructor(public key: string, public key1: string, public key3: string) {
    }
}

mapTo([new KeyValue('a', 'b', 'c')], { key: 1 }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key: { key1: 1 } }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: 1 } }); //-> okay 
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: { key3: 1 } } }); //-> okay
mapTo([new KeyValue('a', 'b', 'c')], { key1: { key: { key4: 1 } } }); //-> error // key4 not exist
mapTo([new KeyValue('a', 'b', 'c')], { key: { key: 1 } }); //-> error, key appears twice 

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

Is Ruby on Rails featured in Designmodo's Startup Framework Kit?

I'm curious if the Startup Framework Kit from Designmodo can be seamlessly incorporated into my Ruby on Rails project. While I've had success integrating their Flat-UI-Pro using a gem, I haven't come across one for the Startup Framework yet. ...

Looping through items with ng-repeat and creating a submenu with M

When constructing a menu from a JSON file with submenus using the JQuery.mmenu plugin, I encountered an issue when trying to implement the submenu structure with ng-repeat. The raw HTML approach worked perfectly, but as soon as I introduced ng-repeat to dy ...

Update the content of the page without reloading images

Is there a way to refresh a webpage on click without refreshing the images, only the text content? Can this be achieved without clearing the cache? I attempted to refresh the entire page with the following JavaScript code: <script> $(".secon ...

Exploring Transformation in Angular

I am looking to enhance my understanding of how ChangeDetection works, and I have a query in this regard. When using changeDetection: ChangeDetectionStrategy.OnPush, do I also need to check if currentValue exists in the ngOnChanges lifecycle hook, or is i ...

The syntax comparison between CommonJS and AMD modules in a modular AngularJS application

Apologies if this question has already been addressed, but I couldn't find any relevant information. Currently, I'm in the process of refactoring a large AngularJS application by creating components as AMD modules. The build process (grunt) utili ...

Having difficulty automatically populating a textarea with the chosen option from a datalist

Is there a way to automatically populate the Address field of a client in a textarea based on the input of the client's name in an input field? I have created a 'for loop' to retrieve a datalist of client names. For the address, I retrieved ...

Cannot retrieve authorization cookie

Currently, I am in the process of setting up backend authentication using Express, Node, and Supabase for my frontend built with React. //auth.js import { supabase } from "../config/supabaseConfig.js"; export const checkAuthorizationStatus = asy ...

elimination of nonexistent object

How can I prevent releasing data if two attributes are empty? const fork = [ { from: 'client', msg: null, for: null }, { from: 'client', msg: '2222222222222', for: null }, { from: 'server', msg: 'wqqqqqqqq ...

What is the best way to retrieve a specific property or attribute of a specific div element after obtaining it from e.target.parentNode?

e.target.parentNode will return this element. <div class="quantity"> <span class="glyphicon glyphicon-minus-sign"></span> <span class="product_Count"> 4 </span> <spa ...

Retrieve an item from an array using AJAX

I am working on a function using ajax that retrieves a set of values: $.each(data.dataa, function (i,item) { $.each(item, function (index, dat) { $str+=dat; }) $ulSub.append( '<li id="'+item.id +'" class="ui-widget-c ...

How to toggle the visibility of an element in an array using AngularJS and JavaScript

Is there a way to show additional information when an item in ng-repeat is clicked, and then hide this extra info when the mouse leaves that same item? One issue I am facing with the code snippet below is that when a user clicks on a different item, it al ...

Potentially undefined object that may be nested and destructured

Here is a snippet of my auto-generated query types: export type MatchLivePlayerType = { __typename?: 'MatchLivePlayerType'; playbackData?: Maybe<MatchPlayerLivePlaybackDataType>; }; export type MatchPlayerLivePlaybackDataType = { __t ...

Managing global errors and intercepting requests in AngularJS can be easily achieved by utilizing $resource interceptors and global handlers for

My question pertains to the interceptor(responseError) of $resource. It is essential to note that I am working with angularjs version V1.3.6. The Issue: app.factory('authInterceptor',['$q', '$location', '$log', fun ...

"Using Callbacks for Enhanced Functionality in Your Alexa

I'm currently facing an issue with my Alexa Skill. Here's the code snippet in question: var options = { method: 'GET', url: 'http://98f8cd20.ngrok.io/products', headers: { 'Postman-Token': &apos ...

Ways to troubleshoot and verify values in PHP that are sent through AJAX

In my jQuery function, I am using AJAX to send values to a PHP file: $.ajax({ //make ajax request to cart_process.php url: "cart_process.php", type: "POST", dataType: "json", //expect json value from server data: { quantity: iqty, ...

How can I retrieve an array from the server side using AngularJS?

Currently, I'm involved in developing a web application meant for team collaboration. While the login and signup pages have been set up, other members of my team are focusing on the server (built with node.js and express framework) and database aspect ...

The HTML element containing a React variable is failing to render ASCII characters

I am encountering an issue where a custom title, received and set in a JS variable, is displaying the ASCII code instead of the symbol. To illustrate, here is a basic example of the render function: render() { var title = "My Title&#8482;" retur ...

The Angular Progressive Web App functions properly in ng serve mode, but encounters issues when running with http-server

I'm developing a Progressive Web App (PWA) using Angular. Everything was functioning smoothly until out of nowhere, I started encountering a 404 Error whenever I tried to navigate to a new component while serving in dist/project with http-server. Surp ...

The sticky element should only be active when the visible section is overflowing vertically. There should be no scrollbar if the height is minimal

I'm currently working on a Whatsapp-style navigation bar and facing an issue with the sticky navbar functionality. https://i.stack.imgur.com/Cy3lA.gif Please refer to the details below for more information. To resolve this issue, I have included ...

What could be causing me to not receive the prepackaged error messages from Angular in my WebStorm 8?

Having some trouble here... my angular errors are always so cryptic, like this: I usually manage to figure out the issue on my own, but I'm really hoping someone can offer guidance on how to get those nice error messages that angular supposedly displ ...