Utilizing Typescript to retrieve a specific object property using square brackets and a variable

How can we correctly access a JavaScript object in TypeScript using variable evaluation with bracket notation, such as myObject[myVariable], when the value of the variable is unknown initially?

In the code below, an error occurs due to the uncertainty of the value in x, making it impossible to determine if it is a key of myDictionary:

const myDictionary = {
  key1: 'String 1',
  key2: 'String 2',
  key3: 'String 3',
};

const possibleValuesOfX = [
  'key1',
  'notAKey1',
  'key2',
  'notAKey2',
  'key3',
  'notAKey3',
];

// Simulating a random potential key for myDictionary
const x =
  possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];

// The following produces an error: No index signature with a parameter of type 'string' was found on type '{ key1: string; key2: string; key3: string; }'.ts(7053)
const decode = myDictionary[x]; 

To address this issue, the code attempts to verify whether x is a key of myDictionary before attempting to access it:

const myDictionary = {
  key1: 'String 1',
  key2: 'String 2',
  key3: 'String 3',
};

const possibleValuesOfX = [
  'key1',
  'notAKey1',
  'key2',
  'notAKey2',
  'key3',
  'notAKey3',
];

const x =
  possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];

let decode: string;
if (x in myDictionary) {
  // Still results in the same error as before
  decode = myDictionary[x];
}

However, this approach does not resolve the error.

The error can be resolved by defining

myDictionary: { [key: string]: string }
, but this solution disables auto-complete functionality and offers little additional benefit.

To retain auto-complete while resolving the error, the following method can be utilized:

type myDictionaryKeys = 'key1' | 'key2' | 'key3';
const myDictionary: Record<myDictionaryKeys, string> = {
  key1: 'String 1',
  key2: 'String 2',
  key3: 'String 3',
};

const possibleValuesOfX = [
  'key1',
  'notAKey1',
  'key2',
  'notAKey2',
  'key3',
  'notAKey3',
];

const x =
  possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];

let decode: string;
if (x in myDictionary) {
  decode = myDictionary[x as myDictionaryKeys];
}

Despite resolving the error, this method may seem cumbersome and redundant, requiring the keys to be typed twice—once in the object and once in the type declaration. Is there a more elegant or efficient solution available?

Answer №1

Edit: I have made adjustments to the example based on the question in your comment.


To indicate to the compiler that a value is a key in the dictionary, you can utilize a type predicate like the isDictionaryKey function demonstrated below:

Check out this TS Playground link

function isDictionaryKey <T>(
  dictionary: T,
  str: string,
): str is keyof Omit<T, number | symbol> {
  return str in myDictionary;
}

const myDictionary = {
  key1: 'String 1',
  key2: 'String 2',
  key3: 'String 3',
};

const possibleValuesOfX = [
  'key1',
  'notAKey1',
  'key2',
  'notAKey2',
  'key3',
  'notAKey3',
];

const x = possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];

let decode: string;
if (x && isDictionaryKey(myDictionary, x)) {
  x; // "key1" | "key2" | "key3"
  decode = myDictionary[x];
}

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

What is the best way to implement filter functionality for individual columns in an Angular material table using ngFor?

I am using ngFor to populate my column names and corresponding data in Angular. How can I implement a separate filter row for each column in an Angular Material table? This filter row should appear below the header row, which displays the different column ...

What is the best way to retrieve information from multiple pages of my REST API?

Recently, I integrated a search engine into my application and now I need to gather all the data available for a particular resource, such as all the posts made by a user. The response I receive from my API looks something like this: { "count": 2, ...

Is it possible that React useState is not allowing a default value to be set in this case?

In my chart component, I have the functionality to show/hide specific lines. To keep track of active lines, I maintain an array called activeKeys in a state. Initially, I populate this array by calling a function named getKeys, which takes an array of data ...

Steps for activating the HTML select option menu with an external button click

I'm currently in the process of building a React website and I'm faced with the challenge of customizing select options to align with my design in Figma. Check out this image for reference Here's how I've set it up in my code: const C ...

Ensure your Vue components have type-checked props at compile time when using TypeScript

I have encountered an issue while using Vue.js with Typescript. The code I am working with is pretty straightforward, utilizing vue-class-component and vue-property-decorator. <script lang="ts"> import { Component, Prop, Vue } from 'vue-pro ...

Tips for sending data returned asynchronously from an Observable in Angular from a Child component to its Parent

I am facing a challenge passing Async data from child to parent component. When I try to access console.log(this.values) within the ngAfterViewInit() method in the parent component's HTML page load, it returns an empty value. However, upon clicking th ...

First, download a npm package and integrate it into TSX files

Hello all, I am currently working on my very first project using React, Typescript, and ASP.NET Core. As a beginner in this technology stack, I seek your patience and understanding as I encounter challenges along the way. Right now, I'm facing an issu ...

Error: The specified function in the schema is not valid for the current operation mode

I'm facing an issue with validating a material ui form using Formik and Yup. The error keeps popping up. This is the schema I imported from another file: export const validationSchema = Yup.object({ email: Yup.string() .email('Invalid Ema ...

Ionic Framework: Implementing a search bar in the navigation bar

I am looking to include a search icon in the navbar of my Ionic project <ion-navbar> <ion-buttons left> <button ion-button menuToggle> <ion-icon name="menu"></icon-icon> </button> </ion-bu ...

Exploring the utilization of type (specifically typescript type) within the @ApiProperty type in Swagger

Currently, I am grappling with a dilemma. In my API documentation, I need to include a 'type' in an @ApiProperty for Swagger. Unfortunately, Swagger seems to be rejecting it and no matter how many websites I scour for solutions, I come up empty-h ...

A guide to updating a table in Angular using an API response

My form allows me to select events from a drop-down list and choose a date. Depending on the selected date, it retrieves the number of events that occurred on that specific date. If I select an event and a date where events took place, the "All Events" sec ...

Uniting 2 streams to create a single observable

I am in the process of merging 2 different Observables. The first Observable contains a ShoppingCart class, while the second one holds a list of ShoppingItems. My goal is to map the Observable with shopping cart items (Observable<ShoppingItems) to the i ...

Converting types to "any" and encountering the error message "There are two distinct types with the same name, but they are not related."

I am encountering some challenges while trying to use an NPM module that I developed along with its Typescript typings in another application. To simplify the examples, I will omit properties that are not relevant to the issue at hand. Within my module&ap ...

Challenges Faced with Implementing Active Reports in Angular 9

After following all the necessary steps outlined in this website to integrate Active Reports with Angular 9 (), I encountered an error when trying to compile my app: ERROR in The target entry-point "@grapecity/activereports-angular" has missing dependen ...

Steps for making a GET request from an API in Angular 7

Currently, I am attempting to retrieve JSON data using HttpClient in Angular 7. The code is functioning properly, but I am exploring the option of fetching the data directly from the API URL instead of relying on the const IMAGES array. import { Injectable ...

Retrieving a list of actions triggered: Redux

In my Angular project, I am utilizing Redux to manage state and handle API calls. While exploring the redux devtools, I discovered a comprehensive list of executed actions. Is there a method to access a similar list of actions triggered within my angular a ...

Increasing the value of a TypeScript variable using ngFor in an HTML template can enhance its usefulness

Can you dynamically increase a variable declared in your TypeScript file for each element generated by an ngFor loop in your HTML file? <tbody> <tr *ngFor="let item of invoiceItems"> <td>{{item.ItemName}}</td> <td>{ ...

Is there a specific side effect that warrants creating a new Subscription?

Recently, I had a discussion on Stack Overflow regarding RxJS and the best approach for handling subscriptions in a reactive application. The debate was whether it's better to create a subscription for each specific side effect or minimize subscriptio ...

Tips for effectively jasmine testing with the createSpyObj function, where class properties are defined as spies

When attempting to create a mock service with set-only properties, I encountered errors indicating that the value was undefined despite following the guidance in the documentation here. I want to be able to track the values of these properties during test ...

using the ng2-accordion component in your Angular 2 project

I am having trouble with the angular-2 accordion I implemented. It is not functioning properly and throwing a 404 error. The issue seems to be related to a third-party plugin called "ng2-accordion." I have double-checked the path of the package and it is ...