Properly implement the indexById function

I have a task to create a function called indexById that will accept an Array of objects. Each object in the array will contain a unique id property and may also have different value properties.

The desired outcome is to get an object where the keys are the id values from the array and the corresponding values are the objects themselves, as shown in the example below.

The input array can be directly passed to the function or defined as const.

Implementing the logic in JavaScript is simple. But how can we ensure type safety for the output?


output = getIndexById([
    {
        id: '1',
        value: 'abc'
    },
    {
        id: '2',
        value: 123
    },
    {
        id: '3',
        value: {someProp: 3}
    }
])
  
//expected output
const output = {
    '1': {
        id: '1',
        value: 'abc'
    },
    '2': {
        id: '2',
        value: 123
    },
    '3': {
        id: '3',
        value: {someProp: 3}
    }
}

output.3.value.someProp // typescript should know this is number

Answer №1

Does this meet your requirements?

const result = findElementByAttribute([
    {
        attribute: '1',
        value: 'apple'
    },
    {
        attribute: '4',
        value: 456
    },
    {
        attribute: '2',
        value: {someKey: true}
    }
] as const)

// Attribute: 2
const keyResult = result['2'].value.someKey

type ElementObject = { attribute: string }
type ElementArray = ReadonlyArray<ElementObject>
type ByAttribute<E, O extends Record<string, ElementObject>> =
  E extends readonly [infer H extends ElementObject, ...infer T extends ElementArray]
    ? ByAttribute<T, O & Record<H['attribute'], H>>
    : O

function findElementByAttribute<E extends ElementArray>(arr: E): ByAttribute<E, {}> {
  throw new Error("Not available")
}

Answer №2

To enhance code readability and maintainability, you have the ability to specify interfaces and transmit the expected data types as generics within the outputObject

interface dynamicProps {
    [key: string]: any
}
interface inputData<T> {
  id: string;
  value: T;
}
interface finalOutput {
  [key: string]: inputData<string|number|dynamicProps>;
}
const fetchIndexByLabel = (): finalOutput => {
  return {
    '1': {
      id: '1',
      value: 'abc',
    },
    '2': {
      id: '2',
      value: 123,
    },
    '3': {
      id: '3',
      value: { someValue: 3 },
    },
  };
};

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

Retrieve items from the type group [T, V] where U is not included, and [U, any]. T should be a union type in the context

Some time ago, I shared my query on Inferring the shape of the result from Object.fromEntries() in TypeScript. The response I received seemed to work well for me until a couple of days back. declare global { interface ObjectConstructor { fromEntries& ...

Having trouble showing table data in Angular

My goal is to showcase data from a table created using Spring-Boot Below is my model.ts: export class Quiz1 { QuestionId?: any; Question?: string; OptionsA?: string; OptionsB?: string; OptionsC?: string; OptionsD?: string;} He ...

Definition of DataTypes in TypeScript

My goal seems simple to me, but I am realizing that my experience with Typescript might not be enough. I want to create a type that can accept the following expressions: const dp: DataPoint = [1, 2]; const dp2: DataPoint = [1, 2, 3]; const dps: DataPoints ...

Limit the type of parent to multiple children

Within my application, I have a main object defined with the following structure: type MainObject = { name: string; age: number; city: string; } Now, there is another section in the application that specifically makes use of the properties name, age ...

Using jQuery to bind data to Angular's *ngFor directive

I am currently in the process of customizing a horizontal timeline resembling https://codepen.io/ritz078/pen/LGRWjE/. The demo includes hardcoded dates which I want to replace with an array of Dates (timelineParsedDates) <ol> <li><a href ...

Best practices for transferring date objects between a frontend developed in JavaScript/TypeScript and a backend built in ASP.net Core 5

An exciting project I am working on involves a web application with a backend REST web API developed in ASP.net Core 5 and a frontend Angular application written in TypeScript. One of the APIs from the ASP.net backend returns an instance of a C# object de ...

Expanding the base class attribute in Typescript

I am currently in the process of developing a wrapper class to enhance the functionality of ReactReduxForm's Control component. Below is the initial class/component setup: export class Control<T> extends React.Component<ControlProps<T> ...

retrieve the name or path of the route currently being accessed

Here is the navigation bar code snippet: <nav class="menu"> <a routerLink="textArea" class="menu-item">text-area</a> <a routerLink="dropdown" class="menu-item">dropdown</a& ...

Swapping the content of the API response with Angular 11 in the HTML

When the output of row.remarks is 1, I want to display it as "passed" and when it's 0, I want it to be displayed as "fail" in the HTML while using mat-table. HTML <ng-container matColumnDef="remarks"> <th class="font& ...

When an asyncIterator is implemented in a unit test, it fails to resolve with any values

I am currently working with a readable stream from chatGPT and I am trying to assert it using an asyncIterator. However, despite my jest test running smoothly, there seems to be a logical error preventing it from resolving after each iteration. Can anyone ...

Is there a way to mark a template-driven form as invalid when a custom field validator fails in my Angular 15 application?

Currently, I am working on an Angular 15 app that utilizes a hand-coded JSON file along with the JSON server for performing CRUD operations on a "employees" JSON data. One of the tasks at hand involves adding custom validation to a <select> element. ...

Obtain information from a JSON file based on a specific field in Angular

The structure of the JSON file is as follows: localjson.json { "Product" :{ "data" : [ { "itemID" : "1" , "name" : "Apple" , "qty" : "3" }, { "itemID" : "2" , "name" : "Banana" , "qty" : "10" } ] ...

Creating a type-safe dictionary for custom theme styles in Base Web

In my Next.js project, I decided to use the Base Web UI component framework. To customize the colors, I extended the Theme object following the guidelines provided at . Interestingly, the documentation refers to the theme type as ThemeT, but in practice, i ...

*ngIf - use a property that requires multiple settings

In my Angular 6 project, I have implemented a WIJMO grid in the template that pulls data from a database table. Each row in the grid should display either a delete button or an un-delete button based on the condition specified using *ngIf else: <wj-fle ...

Waiting for an Observable to complete in an Angular map operation

Attempting to send HttpClient in an Observable function without waiting for it to complete. Below is a sample code snippet to replicate the issue: test() { this.test2() .pipe( mergeMap((result) => { console.log(result[0] ...

Vue.js is unable to recognize this type when used with TypeScript

In my code snippet, I am trying to set a new value for this.msg but it results in an error saying Type '"asdasd"' is not assignable to type 'Function'. This issue persists both in Visual Studio and during webpack build. It seems like Ty ...

Creating a notification following the deletion of a user using Typescript and GraphQL

As someone who is new to Typescript and GraphQL, I recently implemented CRUD functionalities in a To-Do list. However, I am facing a challenge when it comes to including messages within GraphQL responses. Specifically, when I delete a User, I would like th ...

AgGridReact - The grid fails to update when there are changes made to the isRowSelectable property

My challenge is to dynamically pass the prop isRowSelectable to an AgGridReact. In this demo scenario, the expected behavior is that clicking the "Switch criteria" button will alter which items in the grid have checkboxes. However, when testing it out, th ...

Improving DynamoDb Query Results with Type Hinting

In the following Typescript code, how can I specify which fields should be present in my Query Items Result? const request: DynamoDB.DocumentClient.QueryInput = { TableName: UnsubscriptionTokensRepository.TABLE_NAME, IndexName: 'TokenIndex&ap ...

Angular2: Ways to update components with resolver dependencies?

In my project, I have three separate components, each with its own resolver that retrieves data from distinct APIs. These components all depend on a shared URL provided by a service. My goal is to ensure that when the URL changes, each component refreshes ...