Using TypeScript interfaces to define key-value pairs for object properties

My goal is to accurately type situations where I need to map an array of objects to an array with the same objects, but using the property value as the index key.

View code on playground

interface ValueDefinition {
    name: string;
}

function getByName<V extends ValueDefinition>(valuDefinitions: V[]) {
    let out  = {}

    for (const key in valuDefinitions) {
        out[valuDefinitions[key].name] = valuDefinitions[key];
    }
    return out;
}

const obj: ValueDefinition = {
    name: 'super'
};


const objKey = getByName([
    obj
]);

key.super; // Typings for this output

I am searching for a solution like this:

type WithKey<D extends ValueDefinition> = {
    [key: D['name']]: D;
}

Thank you.

Answer №1

To ensure flexibility, consider making your ValueDefinition interface generic by specifying the string literal type of the name property:

interface ValueDefinition<K extends string = string> {
    name: K
}

You can then define the output of the getByName() function using a mapped type:

type ValueDefinitionObject<K extends string> = {[P in K]: ValueDefinition<P>}

Adjust the signature of the getByName function to encompass various name literals:

function getByName<K extends string>(valuDefinitions: Array<ValueDefinition<K>>): ValueDefinitionObject<K> {
    let out = {} as ValueDefinitionObject<K>
    for (const key in valuDefinitions) {
        out[valuDefinitions[key].name] = valuDefinitions[key];
    }
    return out;
}

Ensure proper typing when declaring your obj, so that values like 'super' are inferred correctly with an identity function:

function asValueDefinition<K extends string>(vd: ValueDefinition<K>): ValueDefinition<K> {
    return vd;
}

Now you can test it out by creating instances of the objects:

const obj = asValueDefinition({ name: 'super' });
const obj2 = asValueDefinition({ name: 'thing' });

Inspecting them reveals types like ValueDefinition<'super'> and ValueDefinition<'thing'>.

const objKey = getByName([obj, obj2]);  

objKey is now typed as

ValueDefinitionObject<'super'|'thing'>
. Let's utilize it:

objKey.super; // returns ValueDefinition<'super'>
objKey.thing; // returns ValueDefinition<'thing'>
objKey.nope; // error, property 'nope' does not exist

Give it a try! Good luck!

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

Unusual Observable behavior in Angular/Typescript leaves developers scratching their heads

I have encountered an issue with a single Angular 2 service: validate() { return this.http.get('api/validate', data); } Consuming the API works fine: this.ValidationService.validate().subscribe(result => { console.log(&a ...

Unable to transfer object from Angular service to controller

I am currently utilizing a service to make a $http.get request for my object and then transfer it to my controller. Although the custom service (getService) successfully retrieves the data object and saves it in the responseObj.Announcement variable when ...

React: Why aren't class methods always running as expected?

I created a class component that retrieves a list of applications from an external API. It then sends a separate request for each application to check its status. The fetching of the applications works well, but there is an issue with the pinging process ...

Beginner - managing tasks with React and TypeScript

Can someone assist me with a minor issue? I have experience programming in React using pure JavaScript, but I'm struggling with transitioning to TypeScript. I don't quite understand all the hype around it and am finding it difficult to work with. ...

Utilizing ng-class to apply separate conditions to an array of buttons in Angular

I am facing a straightforward issue. I need to create an array of 3 buttons, and upon clicking each button, the background color of the page should change. The catch is that I have to achieve this using pure Angular-TypeScript without the use of JavaScript ...

Enabling specific special characters for validation in Angular applications

How can we create a regex pattern that allows letters, numbers, and certain special characters (- and .) while disallowing others? #Code private _createModelForm(): FormGroup { return this.formBuilder.group({ propertyId: this.data.propertyId, ...

Tips on delaying the return of the Angular compiler until the subscription is complete

I'm facing an issue with a function that needs to return a value while containing a subscription. The problem I'm encountering is that the return line is being executed before the subscription ends, testFunc(){ let objectType; let modul ...

How to assign a value to an array within a form in Angular 8

I'm facing an issue with my Angular 8 edit form that utilizes a form array. When I navigate to the page, the form array is not populated with values as expected. Can anyone help me identify and solve this problem? ngOnInit(): void { // Fetc ...

Switch the MatSlideToggle within an Angular 8 component

I seem to be encountering a persistent error: "ERROR TypeError: Cannot set property 'checked' of undefined" Take a look at my code snippet from test.component.ts: import { Component, OnInit, ViewChild } from '@angular/core'; import { ...

Developing with TypeScript - Utilizing the <reference path="....."> directive

Recently, I encountered an issue while adding a plugin to the TypeScript compiler. After including my code and compiling tsc.ts, it compiled without any errors. However, when I attempted to run it, I noticed that some variables declared in io.ts were missi ...

Issue with Typescript: When inside a non-arrow class method, the keyword "this" is undefined

Many questions have addressed the topic of "this" in both JS and TS, but I have not been able to find a solution to my specific problem. It seems like I might be missing something fundamental, and it's difficult to search for an answer amidst the sea ...

Using TypeScript with Vue and Pinia to access the store

Is it necessary to type the Store when importing it to TypeScript in a Pinia Vue project? // Component <p>{{ storeForm.firstName }}</p> // receiving an error "Property 'storeForm' does not exist on type" // Store ...

Issue with the declaration of custom types in Typescript

I've created a type declaration for r-dom as shown below: /// <reference types="react" /> declare module 'r-dom' { interface IRDOMFacade extends React.ReactDOM { (component: React.Component<any, any>, properties?: ...

Determining the Type<> of a component based on a string in Angular 2

Can you retrieve the type of a component (Type<T>) based on a string value? For example: let typeStr: string = 'MyComponent'; let type: any = getTypeFromName(typeStr); // actual type ...

What is the best way to show/hide group items in a PrimeNG dropdown menu?

Is it possible to show or hide group items when clicking on the group header if the group contains items? For instance, I would like to display 3 items (AA, BB, CC) in a dropdown menu. The first 2 options (AA and BB) should be selectable, but when I click ...

Error: Uncaught TypeError in AuthContext in Next.js 13.0.6 when using TypeScript and Firebase integration

I'm currently trying to display a page only if the user is present in my app. Right now, the app is pretty bare bones with just an AuthContext and this one page. I had it working in React, but ran into some issues when I switched it over to TS and Nex ...

Adding elements from one array to another array of a different type while also including an additional element (JavaScript/TypeScript)

I'm having trouble manipulating arrays of different types, specifically when working with interfaces. It's a simple issue, but I could use some help. Here are the two interfaces I'm using: export interface Group { gId: number; gName: st ...

Each time a tab is visited, the viewDidLoad function is only triggered once for its events subscription

Here's the code snippet I'm working with: import { Component, ViewChild } from '@angular/core'; import { IonicPage, NavController, Nav, App, Tabs} from 'ionic-angular'; @Component({ templateUrl: 'tabs.html' }) e ...

What is the best way to send out Redux actions?

I'm in the process of creating a demo app with authorization, utilizing redux and typescript. Although the action "loginUser" in actions.tsx is functioning, the reducer is not executing as expected. Feel free to take a look at my code below: https:/ ...

Comparing the cost of memory and performance between using classes and interfaces

As I delve into writing TypeScript for my Angular project, one burning question arises — should I use an Interface or a Class to create my domain objects? My quest is to uncover solid data regarding the actual implications of opting for the Class route. ...