Develop a set of matching key/value pairs using TypeScript

Looking to develop a custom data type where InputKeys will serve as the keys, and the values will be key/value pairs. The keys should correspond to InputFieldKey, with the value being a string.

My current progress includes {[key: string]: string}, but I need the key in this context to relate to the main key.

I've successfully established a parent-child relationship using <Record, for the parent part. However, I am struggling with constructing the child part which necessitates another layer of parent/child connections.

There could be varying numbers of ???InputFieldKeys, each containing multiple fields beyond just 3 like (firstName, lastName, ..., ...)

I am open to adjusting the code as needed to achieve the desired structure, and potentially utilizing generics if beneficial.

type InputKeys = 'user' | 'building'

type UserInputFieldKey = 'firstName' | 'lastName' | 'age'
type AddressInputFieldKey = 'line1' | 'line2' | 'zip'

type InputError = Record<InputKeys, {[key: string]: string}>

const errors: InputError = {
  user: {
    firstName: 'First name must be entered',
  },
  address: {},
}

Guidance on this matter would be greatly appreciated.

Answer №1

If you were to manually perform this task, it seems like the structure you're aiming for is as follows:

interface InputErrorManual {
    user: {
        firstName?: string;
        lastName?: string;
        age?: string;
    },
    address: {
        line1?: string;
        line2?: string;
        age?: string;
    }
}

You have the option to do it that way.


If you prefer the compiler to handle it programmatically, then you must specify the parent/child relationship in a mapping type, such as shown below:

type InputKeyMapping = {
    user: "firstName" | "lastName" | "age";
    address: "line1" | "line2" | "zip"
}

You can utilize a mapped type to transform this into the desired structure:

type InputError = {
    [K in keyof InputKeyMapping]: Partial<Record<InputKeyMapping[K], string>>
};

You can confirm that this matches the structure of InputErrorManual.


Now, let's put them to the test:

const goodErrors: InputError = {
    user: {
        firstName: 'First name must be entered',
    },
    address: {},
}; // should work fine

const badErrors: InputError = {
    user: {
        lastName: "bad name",
        line1: "oops" // error!
    },
    address: {
        line1: "bad line",
        age: "oops" // error!
    }
}

Whether using manual or programmatic mapping is more suitable for your scenario, both methods should serve your needs equally well.

Hopefully, this information proves helpful; best of luck!

Playground link to code

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 5+ does not have any compatible call signatures for Type Search

Utilizing an addItem function that I found on this site, I encountered the following error message: Error TS2349 (TS) Cannot invoke an expression whose type lacks a call signature. Type 'Search' has no compatible call signatures. Definition o ...

Click on the div in Ionic 2 to send a variable

<div class="copkutusu" (click)="kanalsil(kanalid,deneme)" #kanalid id={{ver.channelid}} #deneme id={{ver.channelapikey}}></div> I am requesting kanalid.id and deneme.id in my .ts file. Even though they are the same variable names, they repres ...

Tips for effectively using ngOnChanges in Angular 2 to validate inputs without causing the 'Expression has changed after it was checked' error

I attempted to create my own custom component with basic validation using regex that can be passed as input to the component. There are two scenarios to consider: one where the form is initially empty (new item form) and another where data is already prese ...

Ionic Vue is throwing an error indicating that a property is not found on the type '{ $route(currentRoute: any): void; }'

Currently, I am developing an Ionic WebApp using Vue and TypeScript. My current task involves retrieving the current id parsed by the route. To achieve this, I have been working on a watcher: export default { data() { return { ...

HTTP Interceptor never finishes executing (finalization is never triggered)

In my angular 8 project, I created a basic HttpInterceptor that simply duplicates the original request and includes an additional parameter: @Injectable() export class RequestHeadersInterceptor implements HttpInterceptor { intercept(request: HttpReques ...

Tips for simulating or monitoring an external function without an object using Typescript 2 and Jasmine 2 within an Angular 4 application

In order to verify if a function called haveBeenCalledWith() includes the necessary parameters, I am seeking to validate the correctness of my call without actually executing the real methods. I have experimented with multiple solutions sourced from vario ...

The default value in an Ionic select dropdown remains hidden until it is clicked for the first time

Having an issue with my ion-select in Ionic version 6. I have successfully pre-selected a value when the page loads, but it doesn't show up in the UI until after clicking the select (as shown in pic 2). I'm loading the data in the ionViewWillEnt ...

Can you explain the significance of the colon in this context?

Upon reviewing some SearchKit code snippets (composed with react/jsx and es2015), I came across the following line in a jsx file: const source:any = _.extend({}, result._source, result.highlight) I am curious about the purpose or significance of the colo ...

Activate the mat-menu within a child component using the parent component

Incorporating angular 6 along with angular-material, I am striving to trigger the matMenu by right-clicking in order to utilize it as a context menu. The present structure of my code is as follows. <span #contextMenuTrigger [matMenuTriggerFor]="context ...

What is the best way to create three distinct fractions in JavaScript that cannot be simplified?

I have a specific requirement to create 3 fractions with the following conditions: The denominator remains constant The numerator must be unique and fall within the range of 1 to three times the denominator The fraction should not be reducible (e.g., 2/6 ...

What is the process for transferring a Pulumi Output<T> to the container definition of a task in ECS?

When creating a generic ECS service that deals with dynamic data, it is important to note that the containerDefinition within a Task Definition must be provided as a single valid JSON document. The code snippet for this setup looks like: genericClientServi ...

Module not found in Typescript

Filter.ts, mustache.js and redux.3.5.2.js are all located in the same directory (/Scripts). The code snippet within Filter.ts is as follows: ///<reference path="./typings/mustache.d.ts" /> import Mustache = require("mustache"); import Redux = requir ...

Disabling dynamic color updates upon refresh

I am currently using chartjs and I want to generate new random colors each time the page is refreshed. However, I need these colors to remain fixed and not change after a page refresh or reload. Below is the function I am working with: getRandomRgb() { ...

Tips for expanding third-party classes in a versatile manner using Typescript

tl;dr: Seeking a better way to extend 3rd-party lib's class in JavaScript. Imagine having a library that defines a basic entity called Animal: class Animal { type: string; } Now, you want to create specific instances like a dog and a cat: const ...

Validator for IP addresses in Angular reactive forms

Hey there, I'm currently trying to implement a validator for an IP address in Angular. Strangely, even when I input an invalid IP address like 12.2.2.2..., the GUI indicates it is valid (as shown in the image). However, the console logs reveal that it ...

TensorflowJS Error: The property 'fetch' cannot be read as it is undefined

I am working on an Angular 7 application and attempting to load the mobilenet model by following the instructions in this example. To do this, I first installed tensorflowjs using the command npm install @tensorflow/tfjs (based on the steps provided in th ...

Ways to Access HTTP Request Headers in Angular 6 upon Page Load

Is it possible to retrieve request header information in Angular 6/7 upon application initialization? I specifically require access to header values for security and access management purposes, as these values are set in the headers during the usage of th ...

Creating interactive forms - Incorporating dynamic checkbox options within the expansion panel element

Recently, I developed a basic movie list app with a checkbox list for genre filtering. Initially, I managed to achieve the desired functionality without using reactive forms. However, I am now exploring implementing the same functionality using reactive ...

Ensuring type safety for functions with multiple definitions in TypeScript

The code provided above is prone to failure. TypeScript may mistakenly infer the return type as `string`, allowing you to use the `charAt` method on it even though the actual type is `number`. Is there a solution to enhance the code in a way that TypeScri ...

When using `JSON.stringify`, the resulting data may vary from the original object

Here is the code snippet in question: console.log("444444: ", profile, JSON.stringify(profile)) Upon checking the log output: https://i.stack.imgur.com/LzalV.png I am trying to understand why I cannot see the value: [0] present Additionally, ...