The index access type cannot be used with T[Key extends keyof T]

My work frequently involves arrays structured like this:

[
{key1: val1, key2: value2, key3: val3},
{key1: val1, key2: value2, key3: val3},
{key1: val1, key2: value2, key3: val3}]

and I often need to convert them into a dictionary/map format, for example:

[val1FromFirstElement]: {key2: val2, key3, val3},
[val1FromSecondElement]: {key2: val2, key3, val3},
[val1ThirdElement]: {key2: val2, key3, val3}}

I usually use a reduce method, but it can make the code look cluttered. I am looking to create a versatile helper function that ensures the array being mapped has the specified key (in this case, key1).

function toDictionary<T, Key extends keyof T> (array: T[], key: Key) {
  return array.reduce((prev, cur: T) => {
      return{...prev, ...{[cur[key]]: cur}};
  }, {})
}

The issue arises when using [cur[key]], as it results in a compile error stating

A computed property name must be of type 'string', 'number', 'symbol', or 'any'.

I understand that index access types are limited to number | string | symbol, but I don't see why I should have to specify any other type since TypeScript should already know that keys can only be one of these types. Am I missing something?

I'm hopeful that someone can enlighten me on where my misunderstanding lies.

Answer №1

The issue you are facing stems from the fact that T in the function toDictionary lacks constraints, leading to ambiguity with the Key. Essentially, the current implementation allows any type for T.

Illustratively, try invoking the function as toDictionary([3, 4, 5], ""). The first parameter will go through smoothly because T[] can correspond to any array due to the unconstrained nature of T. However, the second parameter will trigger an error since the only valid keyof types for elements in a number array like [3, 4, 5] are prototype properties such as toString, toFixed, and others. Surprisingly, even though it may not align with your intentions,

toDictionary([3, 4, 5], "toString")
would satisfy your typing requirements.

The crux of the matter lies in specifying that T should exclusively encompass types with keys, akin to the example you provided with

{key1: val1, key2: value2, key3: val3}
. Therefore, constraining T to extends Record<string, any> enforces that T must be an object indexed by strings per your examples. This approach resolves the typing dilemma:

function toDictionary(array: T[], key: Key) {
  return array.reduce((prev, cur: T) => {
      return {...prev, ...{[cur[key]]: cur}};
  }, {})
}

Consequently, the prior contrived scenario

toDictionary([3, 4, 5], "toString")
now fails appropriately.

You can further refine your constraint by explicitly defining

T extends {key1: any, key2: any, key3: any}
to restrict usage to objects adhering to that structure. The level of specificity hinges on your intended application.

(Side note: There's ambiguity regarding the expected behavior if the passed array contains multiple items with identical values for key1. Currently, your function simply overwrites previous values with those encountered later in the iteration; this might not align with your desired outcome.)

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

Vue and TypeScript: The elusive 'exports' remains unidentified

Since switching my App.vue to utilize typescript, I am facing a compiler error: [tsl] ERROR in \src\main.ts(2,23) TS2304: Unable to locate the name 'exports'. If I have vue-serve recompile after making changes, I encounter t ...

I am unable to retrieve the values from a manually created JavaScript list using querySelectorAll()

const myList = document.createElement("div"); myList.setAttribute('id', 'name'); const list1 = document.createElement("ul"); const item1 = document.createElement("li"); let value1 = document.createTe ...

The npm build command is triggering an error message that reads "Allocation failed due to ineffective mark-compacts near heap limit."

I'm currently working on a ReactJS/TypeScript project on Windows 10. I've been running into issues when trying to build my TypeScript scripts using the following command: "rimraf ../wwwroot/* && react-scripts-ts build && copyfi ...

Verifying TypeScript Class Instances with Node Module Type Checking

My current task involves converting our Vanilla JS node modules to TypeScript. I have rewritten them as classes, added new functionality, created a legacy wrapper, and set up the corresponding Webpack configuration. However, I am facing an issue with singl ...

"Customizing API requests based on specific conditions with n

For a specific scenario, I need to login as an admin in one case and as a regular user in another. signIn$ = createEffect(() => this.actions$.pipe( ofType(AuthActions.signInRequest), exhaustMap(({ variables, redirectTo, hasAdmin }) =&g ...

Ways to delete a class in typescript

There's a menu on my website with li tags containing an a element for navigation. Everything is working fine, but I'm facing an issue where I need to remove all elements with the class seleccionado and only add it to the clicked li. I tried using ...

I am experiencing an issue with React Select where it does not seem to recognize the value I have

Forgive me if this question sounds naive, I am still relatively new to Reactjs, I kindly ask not to suggest using Hooks as they are not compatible with my current project. Currently, I am focusing on a form and its validation process. Here is the snippe ...

typescriptIs it possible to disregard the static variable and ensure that it is correctly enforced

I have the following code snippet: export class X { static foo: { bar: number; }; } const bar = X.foo.bar Unfortunately, it appears that TypeScript doesn't properly detect if X.foo could potentially be undefined. Interestingly, TypeScript ...

Netlify failing to build CRA due to inability to locate local module for method?

I encountered an issue with deploying my site on Netlify. The problem arises when it fails to locate local modules. Below is the log: 12:54:43 AM: Build ready to start 12:54:45 AM: build-image version: 09c2cdcdf242cf2f57c9ee0fcad9d298fad9ad41 12:54:45 AM: ...

What could be causing the Angular router outlet to not route properly?

Check out this demo showcasing 2 outlets (Defined in app.module.ts): <router-outlet></router-outlet> <router-outlet name="b"></router-outlet> The specified routes are: const routes: Routes = [ { path: 'a', com ...

Construct an outdated angular project from scratch

I'm facing an issue with an old Angular project that I'm trying to build. After pulling down the code, running npm install @angular/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc9f9095bccdd2cbd2c8">[email p ...

An error occurs when trying to use AWS.Comprehend as a constructor in the aws JavaScript SDK

I'm attempting to utilize the Amazon Comprehend API using the AWS JavaScript SDK. However, I keep encountering Uncaught (in promise): TypeError: undefined is not a constructor (evaluating 'new AWS.Comprehend... ' What am I doing incorr ...

Having trouble with VSCode/tsconfig path configurations, as the files are being fetched but still receiving a "Module not found" error in the editor

Since I began working on this project, I've been encountering a peculiar issue. When importing modules and files in my Angular components/classes using import, I face an error in VSCode when the paths use the base path symbol @. Strangely enough, desp ...

React Bootstrap Forms: The <Form.Control.Feedback> element is failing to display when the validation is set to false

Problem: I am facing difficulties with displaying the React Bootstrap <Form.Control.Feedback></Form.Control.Feedback> when the validation is false in my form implementation. Steps to Recreate: Upon clicking the Send Verification Code button, ...

What could be the root cause behind the error encountered while trying to authenticate a JWT?

I've been working on integrating a Google OAuth login feature. Once the user successfully logs in with their Google account, a JWT token is sent to this endpoint on my Express server, where it is then decoded using jsonwebtoken: app.post('/login/ ...

Generic partial application fails type checking when passing a varargs function argument

Here is a combinator I've developed that converts a function with multiple arguments into one that can be partially applied: type Tuple = any[]; const partial = <A extends Tuple, B extends Tuple, C> (f: (...args: (A & B)[]) => C, ...a ...

Incorporate an image icon into an Angular grid

Currently, I am in the process of building a web application using Angular. The main goal is to create a grid and color specific cells based on data input. Below is the snippet of my HTML code: <mat-grid-list cols="10"> <mat-grid-tile * ...

Encountering an issue with a MEAN application using Angular 2: The error message states "Cannot read property

As a first-time application developer, I am working on creating a system to manage Client profiles. Utilizing the Angular tour of heroes for the basic structure, I integrated mongodb and express components sourced from various online platforms. However, I ...

What are some alternatives for integrating React production build files apart from utilizing Express?

Is there a way to integrate React into my library using the HTTP module? I'm trying to figure out how to recursively send static files. Specifically, I want to include the build folder from the React production build, but I'm not sure how to go a ...

Transform Text into Numeric Value/Date or Null if Text is Invalid

Consider the TypeScript interface below: export interface Model { numberValue: number; dateValue: Date; } I have initialized instances of this interface by setting the properties to empty strings: let model1: Model = { numberValue: +'', ...