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 are the steps to implementing MSAL in a React application?

Struggling to integrate the msal.js library with react. Post Microsoft login, redirecting to callback URL with code in the query string: http://localhost:3000/authcallback#code=0.AQsAuJTIrioCF0ambVF28BQibk37J9vZQ05FkNq4OB...etc The interaction.status re ...

Make sure the static variable is set up prior to injecting the provider

In our Angular6 application, we utilize a globalcontextServiceFactory to initialize the application before rendering views. This process involves subscribing to get configuration from a back-end endpoint and then using forkJoin to retrieve environment app ...

Angular 2 Popup Modal Issue: "Expression modified after checking"

See the problem in action on YouTube Check out the GitHub repository for the demo app My simple app consists of an app component, a child component (account), and an alert service that handles a message dialog component (popup modal). To demonstrate the ...

How to access the types of parameters in a function type

I am working on a function that takes a value and default value as arguments. If the value is a boolean, I want the return type to match the type of the default value. Here is the function I have: export type DetermineStyledValue<T> = ( value: str ...

Merely using Array.isArray check is insufficient to prompt the TypeScript compiler about a potential array value

I have a method where the type can be an array, but I need to verify that it is not an array before accessing the argument. However, despite my check, I am still encountering the following error (excerpt) on line this.setState({ cuisine });: The type &ap ...

What is the proper error type to use in the useRouteError() function in react-router-dom?

In my React project, I am utilizing the useRouteError() hook provided by react-router-dom to handle any errors that may arise during routing. However, I'm uncertain about the correct type for the error object returned by this hook. Currently, I have ...

I am trying to replace the buttons with a dropdown menu for changing graphs, but unfortunately my function does not seem to work with the <select> element. It works perfectly fine with buttons though

I am currently working on my html and ts code, aiming to implement a dropdown feature for switching between different graphs via the chartType function. The issue I am facing is that an error keeps popping up stating that chartType is not recognized as a ...

Navigation arrows for sliding`

Is there a way to add custom right/left arrows to the Ionic slider component? Demo: Check it out on Stackblitz Note: Make sure to refer to the home.html page for more details. .html <ion-slides [pager]="true" [slidesPerView]="2"> <ion ...

Dealing with React and Firebase Authentication Errors: How to Handle Errors for Existing Accounts with Different Credentials

According to the documentation at https://firebase.google.com/docs/auth/web/google-signin#expandable-1, when error.code === 'auth/account-exists-with-different-credential', signInWithPopup() should return an error.email. However, in my specific c ...

What is the best approach to defining a type for a subclass (such as React.Component) in typescript?

Can someone help me with writing a type definition for react-highlight (class Highlightable)? I want to extend Highlightable and add custom functionality. The original Highlightable JS-class is a subclass of React.Component, so all the methods of React.Com ...

Necessary Typescript class property when executing code

Is there a way to determine if a class property is required in Typescript at runtime? export class A { public readonly ab?: number; public readonly ac?: number; public readonly ad: number; public readonly ae: number; } Can emitDecoratorMetadata o ...

Is there a way to retrieve the modal's viewport height in Angular?

Is it possible to determine the viewport height of my ng bootstrap modal within my Angular application? Here is what I currently have: I have a modal with CSS styling as shown below: .modal-xxl { width: 95% !important; max-height: 90% !important; ...

Check to see if the upcoming birthday falls within the next week

I'm trying to decide whether or not to display a tag for an upcoming birthday using this boolean logic, but I'm a bit confused. const birthDayDate = new Date('1997-09-20'); const now = new Date(); const today = new Date(now.getFullYear( ...

Obtain the data from onTouchTap action

Currently, I have a class that is returning an event to the parent. My goal is to extract the number of the touched button (the label on RaisedButton). Although I am successfully returning the event, I am unable to locate the desired information when I l ...

Troubleshooting offline pagination with dynamic MatTable containing matInputs (Angular 5 Material Design)

I have an issue with my component that contains an empty form with matInputs, as well as a mat-table with matInputs in the rows, all enclosed in mat-cards. The number of rows in the table is dynamic and based on another input called 'range'. So, ...

Issue with triggering Observable during an Angular 2 HTTP call

In my current setup using Ionic 2 with Angular 2, I have the following method implementation: private login(params: any, url: string){ var p = new Promise<JsonResult>((resolve, reject) => { let body = JSON.stringify(params); l ...

Troubleshooting compatibility issues between Sailsjs Services and TypeScript in Vscode

Having an issue with TypeScript in a Sails.js application. I am utilizing TypeScript to write my controller and attempting to use Sails.js services within the controllers. However, I encounter a syntax error in VSCODE. Below is the code snippet from MyCo ...

Fire the props.onChange() function when the TextField component is blurred

Currently, I am in the process of developing a NumberField component that has unique functionality. This component is designed to remove the default 0 value when clicked on (onFocus), allowing users to input a number into an empty field. Upon clicking out ...

What is the best way to configure the default entry point for a package.json file in a React

I'm having trouble with the default export in my package.json file. when I try to import: import { Component } from 'packagename/'; // size 22kb or import { Component } from 'packagename/dist' // size 22kb; but import { Component ...

Minimize the cyclomatic complexity of a TypeScript function

I have a typescript function that needs to be refactored to reduce the cyclometric complexity. I am considering implementing an inverted if statement as a solution, but it doesn't seem to make much of a difference. updateSort(s: Sort) { if (s.ac ...