Versatile typing capabilities

Is it possible to have a function that takes a configuration object as its parameter, specifying which properties in a data object should be read? The configuration object has two properties that correspond to keys in the data object.

The configuration object is structured like this:

const config = {
    rootPropName: 'root',
    relationPropName: 'children',
}

The data object is flat but can form nested structures based on the specified relationPropName.

type ValidKeyTypes = string | number | symbol;

type Input = {
    [key in ValidKeyTypes]: {
        name: string,
        children: (keyof Dummy)[]
    }
}

const data: Input = {
    abc: {
        name: 'ABC',
        children: []
    },
    def: {
        name: 'DEF',
        children: ['ghi']
    },
    ghi: {
        name: 'GHI',
        children: []
    },
    root: {
        name: 'ROOT',
        children: ['abc', 'def']
    }
}

Main function

type Config<T> = {
    rootPropName: keyof T;
    relationPropName: keyof T[keyof T];
}

const iterateFlatObject = <T extends object>(config: Config<T>, data: T) => { ... }

Using main function

iterateFlatObject<Input>(config, data);

This code snippet results in an error message regarding type compatibility when configuring the function. This leads to the question of how to create a dynamic configuration type that provides accurate autocompletion and validates properties against the provided data object.

  • Suggestions on improving functionality are appreciated.

Please reach out if further clarification is needed.

Answer №1

The argument config is of type Config<Input>. Here's the expanded version:

{
    rootPropName: ValidKeyTypes;
    relationPropName: "name" | "children";
}

On the other hand, the inferred type of conf is:

{
    rootPropName: string;
    relationPropName: string;
}

The latter cannot be assigned to the former due to it being more general, which triggers an error.

Instead, you can define conf with an additional as const, instructing the compiler to infer the narrowest or most specific type possible. (More details here). Like this:

const conf = {
    rootPropName: 'root',
    relationPropName: 'children',
} as const

The inferred type of conf will then be:

{
    readonly rootPropName: "root";
    readonly relationPropName: "children";
}

This updated type can now be assigned to Config<Input> and resolve the error.

(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

Angular Material's autocomplete feature allows users to easily search

I am currently working on creating an Angular Material Autocomplete feature. At the moment, I have successfully displayed the options and when selected, the correct name is inserted into the input field. However, my next task is to enable filtering of the ...

TSX implementation of a paginator with an ellipse in the center

Looking to add ellipses in the Pagination, specifically when there are more than 10 pages (e.g., 1 2 3 4 ... 11 12 13 14). I've tried various methods but need guidance as a beginner. Can anyone suggest changes based on my code to help me achieve this? ...

Developing with Electron JS and TypeScript - Leveraging TS-Node in the primary process

Is there a way to modify the code below in order for the electron main process to utilize Typescript by using ts-node? "scripts": { "shell": "cross-env NODE_ENV=development electron ts-node ./app/main.ts" } ...

Experiencing TypeScript error in VSCode while trying to run in Nodejs? Here's how to troubleshoot and resolve

Experimenting with the performance measurement code provided by Nodejs in VSCode has been an interesting challenge for me. I encountered no issues running the code in Nodejs, and it executed smoothly. However, when attempting to run the code in VSCode, er ...

Creating synchronization mechanisms for events in JavaScript/TypeScript through the use of async/await and Promises

I have a complex, lengthy asynchronous process written in TypeScript/JavaScript that spans multiple libraries and functions. Once the data processing is complete, it triggers a function processComplete() to indicate its finish: processComplete(); // Signa ...

Creating an Ionic 3 canvas using a provider

I recently followed a tutorial on integrating the canvas API into Ionic, which can be found at this link. However, I encountered an issue where all the canvas-related functions had to be placed within the pages class, making it quite cumbersome as these f ...

What is the process for updating the internal TypeScript version in VS Code?

When using VS Code, I noticed it comes with its own TypeScript version: Is there a way to update this? The current version is 4.9.3. ...

How Typescript Omit/Pick erases Symbols in a unique way

Recently, I have delved into TypeScript and started working on developing some custom utilities for my personal projects. However, I encountered an issue with type mapping involving Pick/Omit/Exclude and other typing operations where fields with symbol key ...

Issue with Angular project: View not being updated when using behaviorSubjects

Within my Angular project, I am retrieving data from an API using a service and storing the data within a BehaviorSubject as shown below private categorySubject = new BehaviorSubject<number | null>(null); apiBehavior = new ReplaySubject<ApiRes ...

Angular Material Popup - Interactive Map from AGM

I am in the process of developing a material dialog to collect user location information using AGM (angular google maps). I have successfully implemented a map on my main page, but when the dialog is opened, it only shows a blank space instead of the map. ...

Bug in timezone calculation on Internet Explorer 11

I've spent hours researching the issue but haven't been able to find any effective workarounds or solutions. In our Angular 7+ application, we are using a timezone interceptor that is defined as follows: import { HttpInterceptor, HttpRequest, H ...

Running a method at any given time within an ngFor loop in Angular 5

On my angular page, I am facing a challenge with updating a variable and displaying it in the HTML within an *ngFor loop. Here is an example of what I need: HTML: <table *ngFor="let data of Dataset"> somehowRunThis(data) <div>{{meth ...

Using Dropbox for seamless navigation

My navigation using Dropbox is not redirecting to the selected page as expected. Below, I have provided code and a demo for your reference. App Routing Module import { NgModule } from '@angular/core'; import { CommonModule } from '@angular ...

The preflight request in Angular2 is being rejected due to failing the access control check: The requested resource does not have the 'Access-Control-Allow-Origin' header

I encountered an issue while attempting to execute a basic POST request to establish an account using an API in .NET. The process fails with the mentioned warning title. Interestingly, performing the same request in Postman (an API testing tool) yields a s ...

Concealing a VueJs component on specific pages

How can I hide certain components (AppBar & NavigationDrawer) on specific routes in my App.vue, such as /login? I tried including the following code in my NavigationDrawer.vue file, but it disables the component on all routes: <v-navigation-drawer ...

Declaration in Typescript for an array of strings that will be returned as a

I am facing an issue with my async function that is supposed to return either a single string or an array of strings. Here is the relevant code snippet: async getAllAnnotationTimes(): Promise<string> | Promise<string[]> { return aw ...

Is there a way to transfer data from a custom hook to a component seamlessly?

I am facing an issue with a custom hook that passes parameter data along with fetched data to the Settings component. Inside Settings, I have a hook called setData11 in useEffect and I am trying to set the data passed from useTable but encountering an er ...

Diverse Selection of Font Awesome Icons

In my React project with TypeScript, I have a header component that accepts an Icon name as prop and then renders it. I am trying to figure out the best way to ensure that the icon prop type matches one of the existing FontAwesome Icons. import { FontAwe ...

leveraging the import statement in conjunction with SystemJs

Currently, I am in the process of creating a sample code using TypeScript and SystemJS for the browser. In my app.ts file: import {Person,add as test} from './testLib' In the generated app.js file (by TypeScript compiler): var testLib_1 = re ...

Upon initializing an Angular project from the ground up, I encountered an issue where a custom pipe I had created was not

After creating an Angular 16.1.0 application and a custom pipe, I encountered error messages during compilation. Here are the steps I took: Ran ng new exampleProject Generated a pipe using ng generate pipe power Modified the content of app.compone ...