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

The type 'elementfinder' cannot be assigned to a parameter of type 'boolean'

Currently, I am working on a function that checks if a checkbox is selected. If it's not checked, then the function should click on it. However, I encountered an error message stating "argument of type 'elementfinder' is not assignable to pa ...

Experimenting with async generator using Jest

It has become clear that I am struggling with the functionality of this code, especially when it comes to testing with Jest. Despite my efforts to use an await...of loop, I am not getting any output. The file path provided to the generator is correct and I ...

waiting for the import statement in a React/NextJS/Typescript project to resolve

While working on my node.js development server, I encountered a problem with the following code: import { useRouter } from 'next/router' import nextBase64 from 'next-base64'; const Load = () => { const router = useRouter() co ...

How can I ensure that TypeORM, Type GraphQL, Apollo Server, and Azure Functions work together seamlessly?

I have an Azure Function written in TypeScript that utilizes various technologies such as TypeORM, Apollo Server, and TypeGraphQL. The function involves creating resolvers for projects and tasks and establishing a database connection. import { createConne ...

TypeORM issue - UnsupportedDataTypeError

Here is the entity file I'm working with, user.ts: @Entity('users') export class User { @PrimaryGeneratedColumn() id: number | undefined; @Column({ type: 'string', name: 'username', nullable: true }) username: s ...

Develop a new flow by generating string literals as types from existing types

I'm running into a situation where my code snippet works perfectly in TS, but encounters errors in flow. Is there a workaround to make it function correctly in flow as well? type field = 'me' | 'you' type fieldWithKeyword = `${fiel ...

Guide to running asynchronous code synchronously in Angular 5

Currently, I have a function that loops through a list of files and for each file, it triggers an async method to manipulate the image and add it to an array. The problem is that the async calls are occurring simultaneously, causing the UI to freeze. My g ...

Tips for fixing typing problems (Document undefined) while including ES2017 library in the node_modules directory

When working on a legacy TypeScript project running [email protected], I encountered the need to access methods from ES2017, such as the array.includes method. To enable this, I made changes to my tsconfig.json file. Initially, it looked like this: ...

Angular 8: ISSUE TypeError: Unable to access the 'invalid' property of an undefined variable

Can someone please explain the meaning of this error message? I'm new to Angular and currently using Angular 8. This error is appearing on my console. ERROR TypeError: Cannot read property 'invalid' of undefined at Object.eval [as updat ...

Tips for avoiding the error message "Expected 1 arguments, but got 0" when the specified argument is actually `undefined`

Current Typescript Version: 2.6.2 I am in the process of enhancing the type safety of redux beyond what is provided by default typedefs, while also streamlining some of the redundant code. I believe I am edging closer to my desired setup, with just one is ...

Tips for accessing the value from a subscription within a function in Ionic 3

I am working on a function that retrieves a JSON file from a specific URL. The issue I am facing is that I am trying to access a random object from this data within the file, stored in this.data. However, when I attempt to console.log(this.data) outside of ...

Issue in Typescript: The method `clear` or `send` is not recognized in type `unknown` within Protractor framework

Having trouble using clear and sendKeys in Protractor with TypeScript. Could it be that I am missing certain dependencies, as even the click function is giving errors? I have attempted various solutions from Protractor clear() not working, but unfortunate ...

Building an array from scratch in Angular

Below is the URL to access the code: https://stackblitz.com/edit/ng-zorro-antd-start-xz4c93 Inquiring about creating a new array. For example, upon clicking the submit button, the desired output should resemble the following structure: "tasks": [ { ...

Creating a mock instance of a class and a function within that class using Jest

I am currently testing a class called ToTest.ts, which creates an instance of another class named Irrelevant.ts and calls a method on it called doSomething. // ToTest.ts const irrelevant = new Irrelevant(); export default class ToTest { // ... some impl ...

The error message "The element 'router-outlet' is unrecognized during the execution of ng build --prod" appears

I encountered a specific error message when running ng build --prod, although the regular ng build command works without issue. Error: src/app/app.component.html:1:1 - error NG8001: 'router-outlet' is not recognized as an element: 1. If 'rou ...

Using ts-loader with Webpack 2 will result in compatibility issues

Lately, I've been working on setting up a basic Angular 2 (TypeScript) application with Webpack 2 for bundling. However, I'm encountering numerous errors when using ts-loader to process TypeScript (.ts) files. It seems like ts-loader is not excl ...

Can one mimic a TypeScript decorator?

Assuming I have a method decorator like this: class Service { @LogCall() doSomething() { return 1 + 1; } } Is there a way to simulate mocking the @LogCall decorator in unit tests, either by preventing it from being applied or by a ...

I would like to customize the Primeng switch by changing the values from boolean to 'N' or 'Y'

I integrated the primeNg p-switch component into my Angular 2 project. By default, the input switch's values are boolean. However, I would like to have the values set to 'N' or 'Y' instead of true or false. @export class MyCompone ...

Tips for refining search criteria with a combination of checkbox and range slider in Angular 2

In an attempt to refine the results for the array "db," I have implemented three filters: price, duration, and category. I have experimented with using the filter() method to apply these filters. You can find the code I have worked on here: https://stack ...

Troubleshooting Problem with Uploading Several Photos to Firebase Storage

I need assistance with uploading multiple photos to Firebase Storage. Despite my efforts, it seems that the original upload keeps getting overwritten and the folder with the venueID property is not being created. Can someone provide some guidance on this i ...