Discover how to automatically determine type based on a constant property value in Typescript

I need to determine the type of a property from a predefined constant.

const my_constant = {
    user: {
        props: {
            name: {
                type: 'string'
            }
        }
    },
    media: {
        props: {
            id: {
                type: 'number'
            }
        }
    }
} as const;

type Name = keyof typeof my_constant;

type Constructed<T extends Name> = {
    [K in keyof typeof my_constant[T]['props']]: typeof my_constant[T]['props'][K]['type']

                                     // ~~~ Type '"type"' cannot be used to index type ...
}

I'm puzzled by why I can't use "type" as an index but am able to use "props".

If TypeScript can figure out that there is always a "props" attribute, why can't it infer that there is always a "type"?

Is there another approach to obtain the type?

My goal is to achieve something like this:


const user:Constructed<'user'> = {
    name: 'John'
}

const media:Constructed<'media'> = {
    id: 123
}

const user2:Constructed<'user'> = {
    name: 444
    // ~~~ Error
}

const media2:Constructed<'media'> = {
    id: 'something'
    // ~~~ Error
}

Here is the playground link with the exact error:

Playground Link

Answer №1

To properly index a constant in Typescript, you cannot use a string. You need to use the correct key. Make sure to verify if the object contains the attribute type, and consider using a Mapped type to accurately determine the type instead of just "string".

const my_constant = {
    user: {
        props: {
            name: {
                type: 'string'
            }
        }
    },
    media: {
        props: {
            id: {
                type: 'number'
            }
        }
    }
} as const;

type Name = keyof typeof my_constant;

type InferType<T> = T extends {type: infer I} ? I : never;

interface Mapped {
    string: string;
    number: number;
}

type Constructed<T extends Name> = {
    [K in keyof typeof my_constant[T]['props']]: 
        InferType<typeof my_constant[T]['props'][K]> extends keyof Mapped ?
            Mapped[InferType<typeof my_constant[T]['props'][K]>] : never
}

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

Leveraging the Cache-Control header in react-query for optimal data caching

Is it possible for the react-query library to consider the Cache-Control header sent by the server? I am interested in dynamically setting the staleTime based on server instructions regarding cache duration. While reviewing the documentation, I didn&apos ...

Retrieve the value of an ng-select component upon submitting a form

As a newcomer to Angular, I'm seeking guidance on how to properly handle form submissions with NgSelect in my project. Within my new-team.component.html file, I have the following code structure: <app-header></app-header> <div class="c ...

Ways to assign a random color to every card displayed in a screenshot in Angular 6?

[![enter image description here][1]][1] This is the HTML component code: <div class="row"> <div class="col-lg-3 col-md-3 col-sm-6 col-12"> <a href="javascript:void(0)" (click)="openModal()"> <div class="card card-box HYT ...

I am in the process of transitioning my JSX website to TSX and am struggling to figure out the proper placement of my type definitions

As the title suggests, I am in the process of migrating an application that I developed using the Google Maps API for rendering maps. In this app, I display information on maps and include functionality to zoom in when a user clicks on something. The erro ...

The error message states: "There is no 'on' property defined for the type 'FluentRules<any, any> | FluentEnsure<any> | FluentRuleCustomizer<any, any>'."

Currently, I am developing aurelia-validation and encountering an issue with the on method from a different overload (FluentRuleCustomizer) class. The code works fine when using ruleBuilder['on'](field);, however, changing it to ruleBuilder.on(fi ...

Enhance the array by updating objects within it using the spread operator

I'm looking to modify the name of the second object in a javascript/typescript array. Here's my array: let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}] Is there a way to update the name of ...

Refreshing a component within the ngrx/store

Currently utilizing @ngrx/store within my Angular 2 application. The store contains a collection of Book objects. I aim to modify a specific field within one of those objects. Additionally, there is an Observable representing the Book instance I wish to u ...

Exploring Mixed Type Arrays Initialization in Typescript using Class-Transformer Library

In my class, I have a property member that is of type array. Each item in the array can be of various types such as MetaViewDatalinked or MetaViewContainer, as shown below class MetaViewContainer{ children: (MetaViewDatalinked | MetaViewContainer)[]; ...

What steps can be taken to resolve the issue "AG Grid: Grid creation unsuccessful"?

For my project, I decided to use the modular import approach for AG-Grid. This means importing only the necessary modules instead of the entire package: "@ag-grid-community/core": "31.3.2", "@ag-grid-community/react": ...

Encountered an error with API request while utilizing Cashfree in a React Native environment

I'm currently integrating cashfree into my react native app for processing payments. Here is a snippet of the code I'm using: import { CFPaymentGatewayService, CFErrorResponse, } from 'react-native-cashfree-pg-sdk'; import { CFDr ...

Is there a way to convert a typescript alias path to the Jest 'moduleNameMapper' when the alias is for a specific file?

I am currently working on setting up Jest in a TypeScript project. In our tsconfig.json file, we are using path aliases like so: "baseUrl": ".", "paths": { "@eddystone-shared/*": [ "../shared/*" ], "@eddystone-firebase-helpers/*": [ "src/helpers/fire ...

Angular Custom Pipe - Grouping by Substrings of Strings

In my Angular project, I developed a custom pipe that allows for grouping an array of objects based on a specific property: import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'groupBy'}) export class GroupByPipe impleme ...

The parameters 'event' and 'payload' do not match in type

Upon running the build command, I encountered a type error that states: Type error: Type '(event: React.FormEvent) => void' is not assignable to type 'FormSubmitHandler'. Types of parameters 'event' and 'payload&apos ...

Utilizing Angular 11's HostListener to capture click events and retrieve the value of an object

Using the HostListener directive, I am listening for the click event on elements of the DOM. @HostListener('click', ['$event.target']) onClick(e) { console.log("event", e) } Upon clicking a button tag, the "e" object contains the fol ...

What is the correct method for storing a response in an array variable in Angular?

I am looking to save the response data from an API call in a variable and display it in the component.html file. Component.ts file : public coinsHistory = []; this.service.getCoinsHistory().subscribe( (response) => { this.handleCoinsRespon ...

Error: Unhandled promise rejection - The function get is not part of this.categoryMap

I am facing an issue with calling functions of the Map (get, set, keys, etc) within my function. The map I am working with is returned from a firebase query. Here's a snippet of my code: categoryMap = new Map<Number, String>(); //called onInit ...

Automatically modify the data types of elements within an array

For a recent project, I created a class using TypeScript and React to handle images. Here is an example of how my class looks: class MyCustomImage extends Image { oriHeight: number; } Once I uploaded two images, I ended up with an array called 'r ...

Adjust the size of an Angular component or directive based on the variable being passed in

I'm looking to customize the size of my spinner when loading data. Is it possible to have predefined sizes for the spinner? For example: <spinner small> would create a 50px x 50px spinner <spinner large> would create a 300px x 300p ...

I'm facing an issue with the properties of an interface in my code. Despite having everything coded correctly, why am I still encountering errors?

Within this code snippet, an interface named Row is declared. However, when trying to utilize the properties within the code, an error is encountered. Snippet of Code- import { ServerRespond } from './DataStreamer'; export interface Row { pri ...

Tips on setting a singular optional parameter value while invoking a function

Here is a sample function definition: function myFunc( id: string, optionalParamOne?: number, optionalParamTwo?: string ) { console.log(optionalParamTwo); } If I want to call this function and only provide the id and optionalParamTwo, without need ...