Guide on developing a custom object type, with keys that are derived from the values in the original object

I'm attempting to transform an object into a dynamically created type, but I'm having difficulty getting it to work correctly.

Imagine I have the following object:

const constants = {
   filter: 'flr',
   color: 'col'
}

Is there a way for me to create a type that allows for the following:

type MetaData = {
   flr: number
   col: string
}

// JavaScript code
const meta: MetaData = getMeta();
const filterValue: number = meta[constants.filter];

I want the type to automatically update whenever one of the constant values changes.

I attempted to achieve this by trying the following:

type MetaData = {
  [constants.filter]: number
  [k: constants.filter]: number
  [k: any extends constants.filter]: number
}

However, none of these approaches seem to be working, and I am struggling to find a viable solution. Any suggestions for a functional type?

Answer №1

const types = {
  category: 'cat',
  size: 'siz'
} as const; // extremely important

type Types = typeof types; // denotes the type of the types object
type TypesValues = Types[keyof Types] // determines values of the types object
type Data = {
   [K in TypesValues]: any // mapping all keys to values of types object
}

// utilizing
const dataValues: Data = {
  cat: 1,
  siz: 2
}
const filterSize: number = dataValues[types.category];

Description

The crucial step here is defining types with a const assertion, indicating that the object's structure is constant and the inferred types must match precisely. By using const, typeof types accurately identifies the keys and values of the object.

Additionally, we define two types, Types and TypesValues, for simplicity and better readability, reflecting the content of the types object.

Lastly, Data is defined as a map where the keys correspond to all values within the types object. I have kept values as any since no specific constraints were specified.

Any modification to the types object will necessitate updating every instance of the Data type.


If you require the entire Data object to contain values of one particular type, like number, you can achieve this through:

type Data = {
   [K in TypesValues]: number // setting all values to numbers
}

Alternatively, in a more versatile approach:

type Data<V> = {
   [K in TypesValues]: V // assigning V to all values
}

type DataStr = Data<string>
type DataNum = Data<number>

A comment requested an additional feature; the ability to define types representing subsets of the types object with different value types. Here’s how that could be implemented:

// expanded object for demonstration
const types = {
  category: 'cat',
  size: 'siz',
  grade: 'grd',
  price: 'prc'
} as const;

// repeating the previous two types
type Types = typeof types;
type TypesValues = Types[keyof Types];

// creating distinct value groups
type GroupA = Extract<TypesValues, 'cat' | 'siz'>
type GroupB = Extract<TypesValues, 'grd' | 'prc'>

// formulating a generic type to allow key input via the Keys parameter
type Data<Keys extends PropertyKey, Values> = {
  [K in Keys]: Values
}

// combining both types using &
type FinalData = Data<GroupA, number> & Data<GroupB, string>;

// sample usage
const data: FinalData = {
  cat: 1, // should be a number
  siz: 2, // should be a number
  grd: 'A', // should be a string
  prc: 'B' // should be a number
}
const categoryValue = data[types.category];

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

After each save, gulp-typescript is emitting errors, however, it works without any issues upon subsequent saves

I'm facing some uncertainty regarding whether the issue I'm encountering is related to gulp, typescript, or Angular 2. Currently, I am using Angular 2 Beta 6. Here is an example of my typescript gulp task: var tsProject = p.typescript.createPr ...

Utilize Hardhat and NPM to distinguish between unit tests and integration tests efficiently

Struggling with setting up two commands in my package.json for running unit tests and integration tests. I am having trouble defining the location of the testset for each type of testing. Within the scripts section of my package.json, I have created two c ...

Using Typescript and webpack to detect variables that are defined in the browser but not in Node environment

My goal is to create a package that can be used on both servers and clients with minimal modifications required. Some libraries are available in Node but not in a browser, while others are accessible in a browser but not in Node. For instance, when utili ...

What steps should be taken in order to resolve the error message "Type is missing an index signature"?

Is there a solution to this type error? The argument of type 'Query' is causing an issue as it cannot be assigned to the parameter of type 'Input'. This is due to the absence of an index signature in type 'Query'.(2345) In ...

Can Angular 4 experience race conditions?

Here is a snippet of my Angular 4 Service code: @Injectable() export class MyService { private myArray: string[] = []; constructor() { } private calculate(result): void { myArray.length = 0; // Perform calculations and add results to myAr ...

I am working on an Angular application that includes a dynamic form for an attendance system for employees. I am currently trying to figure out how to generate the JSON data

I have a dynamic form in my reactive attendance system for employees. When I click on submit, I need to generate JSON data like the following: { "user_id": "1", "branch_id": "4", "auth_token": "59a2a9337afb07255257199b03ed6076", "date": "2019- ...

"Exploring the incredible powers of Ionic2, Angular2, HTTP requests, and

Despite all the research I've done on observables, I still struggle to grasp how they function. The HTTP request code snippet is as follows: import { Component, OnInit, Injectable } from '@angular/core'; import { Http, Response, Headers, R ...

Fairly intricate React function component declaration with TypeScript

const withAuth = () => <OriginalProps extends {}>( Component: React.ComponentType<OriginalProps & IAuthContextInterface> ) => { } (withAuth()(PrivateRoute)) // this is how the HOC called Could someone simplify what this function d ...

Using references to pass variables in TypeScript [Angular 8]

I have several variables within the html of this component that are assigned their values by the typescript file. The declaration in the html is as follows: <h1>{{myproperty1}}<\h1> <h1>{{myproperty2}}<\h1> <h1>{{myp ...

"What is the best way to access and extract data from a nested json file on an

I've been struggling with this issue for weeks, scouring the Internet for a solution without success. How can I extract and display the year name and course name from my .json file? Do I need to link career.id and year.id to display career year cours ...

Tips for automatically adjusting the row height in a table with a static header

On my page, I have a header, footer, and a single table with a fixed header. You can check out the code in the sandbox (make sure to open the results view in a new window). Click here for the code sandbox I am looking to extend the rows section so that i ...

Exploring the Relationship Between the ngOnInit and ionViewWillLoad Lifecycle Hooks

After a few months of utilizing Ionic Framework (ionic-angular 3.9.2 latest) for developing Progressive Web Apps, I find myself pondering the distinction between ngOnInit and ionViewWillLoad. If my understanding serves me right, ngOnInit is an Angular lif ...

typescriptExtract generic type from TypedDocumentNode<MyType, unknown> using introspection

I am currently utilizing a library that allows me to retrieve the type from a returned variable within a function. const myVar = gql(somestring) // The library function is called gql type myVarType = typeof myVar // The resultant value of myVarType is Typ ...

Do constructors in TypeScript automatically replace the value of `this` with the object returned when using `super(...)`?

I’m having some trouble grasping a concept from the documentation: According to ES2015, constructors that return an object will automatically replace the value of “this” for any instances where “super(…)” is called. The constructor code must ...

Issue with the onClick event in next.js and TypeScript

While working on the frontend development of an app, I encountered a strange issue with the onClick function. The error message I'm seeing is: Type '(e: SyntheticEvent<Element, Event>) => void' is not assignable to type 'Custom ...

Learn how to easily set a radio button using Angular 4 and JavaScript

It seems like a simple task, but I am looking for a solution without using jQuery. I have the Id of a specific radio button control that I need to set. I tried the following code: let radiobutton = document.getElementById("Standard"); radiobutton.checke ...

Retrieving Vue component properties as a data type

I'm facing a dilemma with my Vue components. I want to extract the props from one component and use them as a type instead of a value in another component. Specifically, I have a component where I need to take in an array of props from a different com ...

transitioning from angular cli version 1.7 to version 12

Looking for a detailed guide on upgrading from version 1.7 to the latest Angular version (12/11)? I currently have an app running on version 1.7 and couldn't find a step-by-step process here: upgrading angular Would it be safe to assume that the upgr ...

Troubleshooting problems with resolving deeply nested promises

My approach to utilizing promises has been effective until now. The issue arises when the console.log(this.recipe) returns undefined and console.log(JSON.stringify(recipes)) displays an empty array. This suggests that the nested promises may not be resolvi ...

Tips for resolving the "Page Not Found" error in your NextJs application

I am organizing my files in the following structure src/ ├── app/ │ ├── pages/ │ │ ├── authentication/ │ │ │ ├── SignUp/ │ │ │ │ └── page.tsx │ │ │ └── SignIn/ │ ...