What is the method in TypeScript for defining a property in an interface based on the keys of another property that has an unknown structure?

I recently utilized a module that had the capability to perform a certain task

function print(obj, key) {
  console.log(obj[key])
}

print({'test': 'content'}, '/* vs code will show code recommendation when typing */')

I am eager to implement this feature in my project, but unfortunately, I cannot remember the name of the module and I am uncertain if my memory serves me right (perhaps it's not even possible).

Currently, I am developing a package and have written some code like this:

interface Box {
  content: {
    [key: string]: string
  }
  using: string // key of content 
}

const box: Box = {
  content: {
    'something': 'inside'
  },
  using: 'something'
}

function showBox(box: Box) {
  console.log(box.content[box.using])
}

The content object actually originates from another package using Typescript. Ideally, I would prefer not to encapsulate the type.

In order to aid developers in identifying bugs while coding, I am investigating whether there is a method to validate an invalid Box type like so:

const box: Box = {
  content: {
    'something': 'inside'
  },
  using: 'samething' // trigger an error during type checking
}

Alternatively, I am searching for any approach that can enable IDEs to provide code recommendations indicating that using should be a key within the content object.

At present, my code appears as follows, but it does not align with my desired outcome, and I am stuck on how to proceed further

interface Box {
  content: {
    [key: string]: string
  }
  using: keyof Box['content'] // will result in string | number
}

A big thank you to everyone who responds!

Answer №1

Your solution appears to be correct, however the IDE is not able to provide suggestions because keyof Box['content'] is defined as an arbitrary string. If you have specific requirements for the structure of content, you can define it within the Box interface like this:

interface Box {
  content: {
    something: string;
  };
  // now it only allowed to be 'something', and IDE will suggest it
  using: keyof Box['content'];
}

If the type of your content is actually a parameter (meaning it can vary for different types), you should make it a parameter of the Box interface by creating a generic interface like this:

interface GenericBox<T> {
    content: T;
    using: keyof T;
}

You can then use it in the following way:

// Example interface to fill a box
interface TestContent {
    x: string;
    y: number;
}

const genericBox: GenericBox<TestContent> = {
    content: {x: '', y: 0},
    using: 'x', // now it can be only 'x' or 'y', and IDE will suggest it
};

You can try out this concept on the playground.

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 search is on for the elusive object that Angular 2/4

Why am I encountering the error message saying "Cannot find name 'object'"? The error message is: Error: core.service.ts (19,23): Cannot find name 'object'. This error occurs in the following line of code: userChange: Subject<ob ...

Error: The specified property is not found in type 'never' - occurring with the ngFor loop variable

When working with API responses and dynamically sorting my view, I utilize an ngFor loop. Here's the snippet of code in question: <agm-marker *ngFor="let httpResponses of response" [latitude]= "httpResponses.lat" [longitude]=& ...

Waiting for the response to come by subscribing in Angular

I am encountering an issue while trying to subscribe to an Observable and assign data from the response. The problem is that my code does not wait for the response before executing the console.log(this.newIds) line, resulting in an empty value being logg ...

Tips for transforming a JSON Array of Objects into an Observable Array within an Angular framework

I'm working with Angular and calling a REST API that returns data in JSON Array of Objects like the example shown in this image: https://i.stack.imgur.com/Rz19k.png However, I'm having trouble converting it to my model class array. Can you provi ...

Encountering an issue with top-level await in Angular 17 when utilizing pdfjs-dist module

While using the Pdfjs library, I encountered an error message that reads: Top-level await is not available in the configured target environment ("chrome119.0", "edge119.0", "firefox115.0", "ios16.0", "safari16.0" + 7 overrides) /****/ webpack_exports = g ...

What sets apart using (@Inject(Http) http: Http) from not using it?

Following a recent query, I now have a new question. What sets apart these two approaches? Here is the original code I used: import {Http, HTTP_PROVIDERS} from 'angular2/http'; @Component({ viewProviders: [HTTP_PROVIDERS], ..// constructor(h ...

1. "The power of three vows in the world

I encountered an issue while making three HTTP Post requests in my code. The first two requests are successful, and upon debugging the code, they return the correct values. However, the third request returns undefined. The reason behind making these three ...

What is preventing me from setting the User object to null in my Angular application?

Currently, I am working on a project in Angular and encountering a specific issue. In my service class, the structure looks like this: export class AuthService { authchange: new Subject<boolean>(); private user: User; registerUser(authD ...

Creating a View-Model for a header bar: A step-by-step guide

I am looking to develop a View-Model for the header bar using WebStorm, TypeScript, and Aurelia. In my directory, I have a file named header-bar.html with the following code: <template bindable="router"> <require from="_controls/clock"></ ...

Working with floating point numbers in Node.js with a zero decimal place

NodeJS interprets float values with a zero after the decimal point as integers, but this behavior occurs at the language level. For example: 5.0 is considered as 5 by NodeJS. In my work with APIs, it's crucial for me to be able to send float values w ...

Angular 2 select does not recognize the selected option

In my Angular 2 code, I am using ngFor to populate a dropdown with options. I want a specific option at a certain index to be selected by default. Currently, I tried using [attr.selected]="i == 0" but it ends up selecting the last option instead of the fi ...

Why does Material-UI's "withStyles()" not function properly with a specified constructor in Typescript?

Update: Please note that there was an issue with the constructor generated by IntelliJ IDEA, but it has been fixed. You can find more details here: I'm exploring the use of Material-UI in my application, and I've encountered some challenges wit ...

What is the best approach to creating an array within my formgroup and adding data to it?

I have a function in my ngOnInit that creates a formgroup: ngOnInit() { //When the component starts, create the form group this.variacaoForm = this.fb.group({ variacoes: this.fb.array([this.createFormGroup()]) }); createFormGroup() ...

Ways to switch up the titles on UploadThing

Recently, I started working with the UploadThing library and encountered a situation where I needed to personalize some names within the code. Here is what I have so far: Below is the snippet of code that I am currently using: "use client"; imp ...

Sticky header in React data grid

Is there a way to implement a sticky header for a data grid in react? I have tried various methods but haven't been able to figure it out. Any suggestions would be appreciated. You can find my code sandbox example here. #react code export const Styl ...

How can data be transferred between controllers in Angular 2 without using URL parameters or the $state.go() function?

I've encountered an issue where I need to pass a parameter from one controller to another without it being visible in the URL. I attempted to do so with the following code: this.router.navigate(['/collections/'+this.name], {id: this.id}); ...

Instructions for adding a new property dynamically when updating the draft using immer

When looking at the code snippet below, we encounter an error on line 2 stating Property 'newProperty' does not exist on type 'WritableDraft<MyObject>'. TS7053 // data is of type MyObject which until now has only a property myNum ...

What is the equivalent of a "Class" in Typescript for defining an "Interface"?

I am interested in passing "Interfaces" to a function. Not just a specific interface, but any interfaces. As explained here, for Class, I can handle it as a type. export type ClassType<T> = { new(...args: any[]): T }; function doSomethingWithAnyCla ...

Implementing Immer in Typescript

Recently, I've been exploring the possibility of integrating Immer into my React project that already utilizes Typescript. Unfortunately, I haven't been able to discover a clear guide on how to effectively employ Immer in conjunction with Typescr ...

What is the best way to add items to arrays with matching titles?

I am currently working on a form that allows for the creation of duplicate sections. After submitting the form, it generates one large object. To better organize the data and make it compatible with my API, I am developing a filter function to group the du ...