What is the best way to utilize Object.keys() for working with nested objects?

When working with nested objects, I am trying to access the properties using Object.keys() and forEach(). However, I am encountering an issue when attempting to access the nested keys filteringState[item][el].

Is there a specific way to write a function for this scenario?

interface InitialStateTypes {
    country: {
        "italy": boolean,
    },
    board: {
        "full": boolean,
    },
    transport: {
        "bus": boolean,
        "own": boolean
    },
}

interface FilteringDataTypes {
    country: string[],
    board: string[],
    transport: string[],
}

const collectFilteringData = (filteringState: InitialStateTypes) => {
    let filteringData = <FilteringDataTypes>{};

    Object.keys(filteringState).forEach((item) => {
        Object.keys(filteringState[item]).forEach((el) => {
            if (filteringState[item][el]) {
                if (!filteringData[item]) {
                    filteringData[item] = [el];
                } else {
                    filteringData[item] = [...filteringData[item], el];
                }
            }
        });
    });
    return filteringData;
};


export default collectFilteringData;

Answer №1

To access specific keys within an object in TypeScript, utilize the keyof operator.

For instance:

type Person = { name: string; age: number };
type Key = keyof Person;

For more information, check out this resource: https://www.typescriptlang.org/docs/handbook/2/keyof-types.html

When dealing with nested data:

type Data = { info: {x: number; y: number} };
type Key = keyof Data["info"];

Answer №2

When using the keys method, things can get a bit messy because it only expects to output strings. (This is understandable since JS Object keys are typically strings, but TypeScript handles this differently)

Below is one possible way to handle this:

interface InitialStateTypes {
  country: {
      "italy": boolean,
  },
  board: {
      "full": boolean,
  },
  transport: {
      "bus": boolean,
      "own": boolean
  },
}

interface FilteringDataTypes {
  country: string[],
  board: string[],
  transport: string[],
}

const collectFilteringData = (filteringState: InitialStateTypes):FilteringDataTypes => {
  let filteringData = {} as FilteringDataTypes

  (Object.keys(filteringState) as Array<keyof InitialStateTypes>).forEach((item) => {
      (Object.keys(filteringState[item]) as Array<keyof InitialStateTypes[typeof item]>).forEach((el) => {
          if (filteringState[item][el]) {
              if (!filteringData[item]) {
                  filteringData[item] = [el];
              } else {
                  filteringData[item] = [...filteringData[item], el];
              }
          }
      });
  });
  return filteringData;
};


export default collectFilteringData
  • In this code example, type assertion is used to specify the expected types for TypeScript.
  • It ensures the correct types are passed to the forEach method.
  • The complexity arises from the nested structure, requiring another type assertion to pass in the value for typeof item from the first forEach.

When formatted with Prettier, the code looks like this:

const collectFilteringData = (
  filteringState: InitialStateTypes
): FilteringDataTypes => {
  let filteringData = {} as FilteringDataTypes;

  (Object.keys(filteringState) as Array<keyof InitialStateTypes>).forEach(
    (item) => {
      (
        Object.keys(filteringState[item]) as Array<
          keyof InitialStateTypes[typeof item]
        >
      ).forEach((el) => {
        if (filteringState[item][el]) {
          if (!filteringData[item]) {
            filteringData[item] = [el];
          } else {
            filteringData[item] = [...filteringData[item], el];
          }
        }
      });
    }
  );
  return filteringData;
};

Note

This answer is based on TypeScript 4.6.2, where the keys method is typed as follows:

keys(o: object): string[];

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

Using Node.js and Typescript to bring in external modules from

Attempting to generate a random integer between 1 and 6 using the 'random' library. Here's what I have coded so far: import random from 'random' function rollDice(min:number, max:number) { return Math.floor(Math.random() * (ma ...

Troubleshooting the ReferenceError: Blob is not defined problem with the heic2any library in a Next.js application

Currently, I am encountering an issue where everything is properly implemented and functioning smoothly. However, the main problem arises when I attempt to reload the page, as it results in an error message: ReferenceError: Blob is not defined. This issue ...

Creating a web application using Aframe and NextJs with typescript without the use of tags

I'm still trying to wrap my head around Aframe. I managed to load it, but I'm having trouble using the tags I want, such as and I can't figure out how to load a model with an Entity or make it animate. Something must be off in my approach. ...

Execute the React Native application on Windows by using the command npx react-native run-windows

I recently created a test application using React Native by running npx react-native init Test --template react-native-template-typescript (https://reactnative.dev/docs/typescript). Everything seemed to be working fine, but I encountered an issue where the ...

Automatically divide the interface into essential components and additional features

Consider the following interfaces: interface ButtonProps { text: string; } interface DescriptiveButtonProps extends ButtonProps { visible: boolean, description: string; } Now, let's say we want to render a DescriptiveButton that utilize ...

Mastering the art of debugging feathersjs with typescript on VS Code

I am facing an issue while trying to debug a TypeScript project with FeathersJS using VSCode. Whenever I try to launch the program, I encounter the following error: "Cannot start the program '[project_path]/src/index.ts' as the corresponding J ...

What is the best way to retrieve a soft deleted entity from typeorm in a postgreSQL database?

Can anyone help me figure out how to retrieve soft deleted documents from a PostgreSQL database using TypeORM's find, findOne, or query builder get/getMany methods? I keep getting undefined as the result. Is there a way to access these deleted values? ...

Leverage JSON files for pagination in NextJS

I am currently developing a science website where the post URLs are stored in a static JSON file. ScienceTopics.json- [ { "Subject": "Mathematics", "chapters": "mathematics", "contentList": [ ...

Incompatibility Issues with TypeScript Function Overloading

In the process of setting up an NgRx store, I came across a pattern that I found myself using frequently: concatMap(action => of(action).pipe( withLatestFrom(this.store.pipe(select(fromBooks.getCollectionBookIds))) )), (found at the bottom ...

Error TS2339: Property does not exist on type 'object' - Typescript arrow function issue

In my experience with Angular, I have noticed that I encounter typescript compile errors quite often when using fat arrow functions within an rxjs stream. Despite being able to run the app and having it transpile successfully, I am curious about how to re ...

This TypeScript error indicates that the variable may be undefined (Error code: 18048)

One of the challenges I encountered in my Angular project was with an interface defined in userinterface.ts export interface Done { wordlen: number; word: string; }; I utilized this interface to populate an array like so donearr: Done[] = []; ...

Using Long Polling with Angular 4

I am looking for a way to monitor the progress of a certain task using API calls. To achieve this, I have developed a service that executes these API calls every 1.5 seconds Main Component private getProgress() { this.progressService.getExportPr ...

I am experiencing an issue with applying responsiveFontSize() to the new variants in Material UI Typography

I am looking to enhance the subtitles in MUI Typography by adding new variants using Typescript, as outlined in the documentation here. I have defined these new variants in a file named global.d.ts, alongside other customizations: // global.d.ts import * a ...

Is it possible to establish role-based access permissions once logged in using Angular 6?

Upon logging in, the system should verify the admin type and redirect them to a specific component. For example, an HOD should access the admi dashboard, CICT should access admin2 dashboard, etc. Below is my mongoose schema: const mongoose = require(&apo ...

What is the best way to limit the types of function parameters in TypeScript based on whether the parameter index is even or odd?

My goal is to create a function with an unlimited number of parameters, where the type of each parameter is determined by whether its index is odd or even. For example: flow(isMachineReady(), 'and', isWaterHot(), 'or', isMilkHot(), &ap ...

Oops! The program encountered an issue where it was unable to access the properties of an undefined variable, specifically while trying to

When creating a custom validation function in Angular, I encountered an issue where using a variable within the validation would result in an error: "ERROR TypeError: Cannot read properties of undefined (reading 'file')". This occurred when chang ...

Using TypeScript and NestJs: Spread types can only be generated from object types

I'm encountering an issue while trying to pass two parameters using the spread operator from the book.controller to the book.service.ts service. The error message I'm receiving is: Spread types may only be created from object types It's w ...

What is the best way to link this to a function in AngularIO's Observable::subscribe method?

Many examples use the Observable.subscribe() function in AngularIO. However, I have only seen anonymous functions being used like this: bar().subscribe(data => this.data = data, ...); When I try to use a function from the same class like this: update ...

What kind of Antd type should be used for the form's onFinish event?

Currently, I find myself including the following code snippet repeatedly throughout my project: // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleCreate = (input: any): void => { saveToBackend({ title: input.title, oth ...

Minimize the quantity of data points displayed along the X-axis in a highcharts graph

After making an API call, I received data for a Highcharts graph consisting of an array of datetimes (in milliseconds) and corresponding values (yAxis). The data is fetched every 15 minutes and displayed on a mobile device. When viewing the data monthly, ...