Generate a new data structure by pairing keys with corresponding values from an existing

Imagine having a type named Foo

type Foo = {
  a: string;
  b: number;
  c: boolean;
}

Now, I am looking to create a type for an object containing a key and a value of a designated type T. The goal is for the value's type to be automatically determined based on the key, allowing me to do this:

const kv1: KeyValue<Foo> = {key: 'a', value: 'STRING'};
const kv2: KeyValue<Foo> = {key: 'b', value: 42};
const kv3: KeyValue<Foo> = {key: 'c', value: true};

If I use the following definition:

type KeyValue<T> = {
  key: keyof T;
  value: T[keyof T]
}

... then the values will encompass all properties' values in Foo:

And if I define it like this:

type KeyValue<T, K extends keyof T> = {
  key: K;
  value: T[K]
}

...then while explicitly specifying as KeyValue<Foo, 'a'> allows creating objects that match Foo's property types, using just KeyValue<Foo, keyof Foo> permits each value to take on any type from string | number | boolean, not inferred from the entered key.

The ultimate aim is to achieve scenarios like these:

const kvs: Array<KeyValue<Foo>> = [
  {key: 'a', value: 'STRING'}, // should reject if value is not a string
  {key: 'b', value: 42}, // should reject if value is not a number
  {key: 'c', value: true}, // should reject if value is not a boolean
];

Is there a way to establish the KeyValue type with these limitations, effectively evolving into

KeyValue<Foo, 'a'> | KeyValue<Foo, 'b'> | KeyValue<Foo, 'c'>
without manually listing this union? Essentially, the desire is to infer the value type based on the given key in the current object literal.

Answer №1

It is not possible to represent each key-value pair using a single KeyValue object because it would necessitate partial inference for the key or finding a way to reference the key property within the value property inside the same object.

One solution could be creating a discriminated union with the input object.

type Bar = {
  x: string;
  y: number;
  z: boolean;
}

type KeyValuePair<U> = {
  [Q in keyof U]: {
    key: Q;
    value: U[Q];
  }
}[keyof U];

// Using KeyValuePair<Bar> will result in the following type
// 
// {
//     key: "x";
//     value: string;
// } | {
//     key: "y";
//     value: number;
// } | {
//     key: "z";
//     value: boolean;
// }

const pairs: Array<KeyValuePair<Bar>> = [
  {key: 'x', value: 40}, // ERROR
  {key: 'y', value: true}, // ERROR
  {key: 'z', value: "foo"}, // ERROR
];

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

Exploration of mapping in Angular using the HttpClient's post

After much consideration, I decided to update some outdated Angular Http code to use HttpClient. The app used to rely on Promise-based code, which has now been mostly removed. Here's a snippet of my old Promise function: public getUser(profileId: nu ...

How can I detect if a control value has been changed in a FormGroup within Angular 2? Are there any specific properties to look

I am working with a FormGroup that contains 15 editable items, including textboxes and dropdowns. I am looking to identify whether the user has made any edits to these items. Is there a specific property or method I can use to check if the value of any i ...

Incorporating a polling feature into an HTTP request within Angular 8

How can I implement a polling mechanism in order to fetch the status of a job (type Status) every minute for a service that requests this object with a specific JOB_ID as an argument? retrieveJobStatus$(JOB_ID): Observable<Status> { const url = ...

The React-Typescript error message is stating that the module "react-router-dom" does not have the exported member "RouteComponentProps"

I encountered an issue with my project involving a login page and the usage of "RouteComponentProps". Unfortunately, I received the following error: Module '"react-router-dom"' has no exported member 'RouteComponentProps'. Upon attempt ...

Retrieving the inner text of a dragged element using Angular Material's DragAndDrop feature

Can the inner text of a dragged element be retrieved and utilized in the "onDrop" function within Angular's cdkDragAndDrop feature? onDrop(event: CdkDragDrop<string[]>) { if (event.previousContainer === event.container) { moveItemIn ...

What does it signify when it is stated that "it is not a descendant of the indexer"?

Currently, I am diving into Typescript with the help of this informative guide on indexer types. There is a specific piece of code that has me puzzled: interface NumberDictionary { [index: string]: number; length: number; // okay, length shoul ...

Grouping Columns in an HTML Table using Angular 4

I'm currently faced with the task of retrieving flat data from an API and presenting it in an HTML table using Angular 4. I'm a bit unsure about how to iterate over the data, possibly using a for-each loop. I have attempted to utilize ngFor but I ...

The debugger extension for Visual Studio Code in Chrome, [webkit-debug-adapter], received a response from the target application, but was unable to find any valid target

I am currently working on an Angular/TypeScript application and have been able to debug the TypeScript code in Chrome thanks to the map files. Recently, I decided to install the Debugger for Chrome extension from Visual Studio Marketplace. You can find it ...

The Google APIs sheet API is throwing an error message stating "Invalid grant: account not found"

I need to retrieve data from a spreadsheet using the Sheet API. After setting up a project in Google Cloud Platform and creating a service account, I granted the account permission to edit the spreadsheet. I then downloaded the credentials in JSON format. ...

NGRX refresh does not result in any successful actions

Having an issue with loading users into a mat-selection-list within a form. Everything works fine the first time, but upon page refresh, the selector returns 'undefined'. Initially, both GET_USERS and GET_USERS_SUCCESS are triggered (console log ...

Having trouble utilizing the DatePicker component in my react native application

I've encountered an issue while using DatePicker in react native. Whenever I try to use it, an error pops up saying: "render error a date or time must be specified as value prop". Here is the link to my repository: my github repository const [date, se ...

Error: The @use directive must come before any other rules in Angular

Error message: Issue: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): Error Details: HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js) ...

In Typescript, it is possible to provide values other than undefined for a parameter that is

I experimented with the code below in TypeScript Playground with all settings enabled. My expectation was that the TS compiler would only allow the first call() to be valid. However, to my surprise, all four calls were accepted. Upon inspecting the calls, ...

Issue with debugging Azure Functions TypeScript using f5 functionality is unresolved

I am encountering issues running my Azure TypeScript function locally in VS code. I am receiving the errors shown in the following image. Can someone please assist me with this? https://i.stack.imgur.com/s3xxG.png ...

Exploring the functionality of custom hooks and context in asynchronous methods using React Testing Library

I'm currently testing a hook that utilizes a context underneath for functionality This is how the hook is structured: const useConfirmation = () => { const { openDialog } = useContext(ConfirmationContext); const getConfirmation = ({ ...option ...

The field 'shouldComponentUpdate' cannot be reassigned to itself

I encountered a TypeScript error while using shouldComponentUpdate: The error message states: "Property 'shouldComponentUpdate' in type 'Hello' is not assignable to the same property in base type Component<IProps, any, any>." ...

What is the best way to manage optional peer dependency types while releasing a TypeScript package?

I'm trying to figure out the best way to handle optional peer dependencies when publishing a TypeScript package on npm. My package provides a function that can accept input from either one of two peer dependencies. How should I define these optional p ...

Guide on utilizing the useContext hook in React/Next.js while incorporating TypeScript

As I embark on my journey in the world of TypeScript, I find myself working on a new project in Next.js using TypeScript. My goal is to incorporate authentication functionality into this project by utilizing createContext. Coming from a background in JavaS ...

What is the method for dynamically selecting generics from a function in a union type using Typescript?

Suppose there is a function defined as follows: type FooParams<Params extends unknown[], Result> = { name: string, request: (...params: Params) => Promise<Result> } const foo = <Params extends unknown[], Result>(params: FooParams ...

Converting HTML to PDF with rtl support using the JavaScript library jsPDF

I'm attempting to convert HTML to PDF using jsPDF in an Angular 5 project. Below is the code I have so far: import * as jsPDF from "jspdf"; . . . htmlToPdf(){ var doc=new jsPDF(); var specialElementHandlers = { '#content' : function ...