What is the best way to transform a standard array into a record without losing the specific data types in each position?

Imagine

type Individual = {
  name: string;
  age: number;
};

const john = {
  name: "John",
  age: 28,
} as const;

const emily = {
  name: "Emily",
  age: 35,
} as const;

I am looking to create a function that takes an individual and transforms it into an object with the name of the person as the key and the person object as the value.

If I am working with one individual, I can achieve this by using

function getIndividual<T extends Individual>(individualOption: T) {
  let person = {} as Record<(typeof individualOption)["name"], typeof individualOption>;
  return person;
}

const individual = getIndividual(john); // John: {name: "John", age: 28}
const individualName = individual.John.name; // John

However, when attempting to extend this functionality to accept an array of individuals, the specific types are not correctly identified for each index.

function getIndividuals<T extends Individual>(individualsOptions: T[]) {
  let individuals = {} as Record<
    (typeof individualsOptions)[number]["name"],
    (typeof individualsOptions)[number]
  >;
  return individuals;
}

const individuals = getIndividuals([john, emily]);

const johnName = individuals.John.name; // John | Emily
const emilyName = individuals.Emily.name; // John | Emily

Is there a way to modify this code so that johnName returns "John" and emilyName returns "Emily" instead of a combination of both?

Answer №1

To start with, we'll utilize a utility type to enhance the readability of types displayed in our IDE by removing the need for ampersands:

type Beautify<T> = T extends infer R ? {
  [K in keyof R]: R[K]
} : never

For the actual coding process, we'll make use of mapped types to go through the array and employ key remapping to construct an object where the keys correspond to the elements of the array:

type OrganizePeople<T extends readonly Person[]> = Beautify<{
  [K in T[number] as K['name']]: K
}>

Implementation example:

function fetchPeopleData<T extends readonly Person[]>(peopleArray: T) {
  let peopleData = {} as OrganizePeople<T>;
  return peopleData;
}

Testing phase:


// const people: {
//     Bob: {
//         readonly name: "Bob";
//         readonly age: 32;
//     };
//     Alice: {
//         readonly name: "Alice";
//         readonly age: 43;
//     };
// }
const peopleInformation = grabPeopleInfo([bob, alice]);

const bobName = peopleInformation.Bob.name; // Bob
const aliceName = peopleInformation.Alice.name; // Alice

Playground Link

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 power of negative multiplication in TypeScript and React

I am working with a state variable called sortDirection const [sortDirection, setSortDirection] = useState<1 | -1>(1); My goal is to allow a button to toggle the state variable like this setSortDirection(sortDirection * -1); However, I encounter a ...

What is the best approach for managing Create/Edit pages in Next.js - should I fetch the product data in ServerSideProps or directly in the component?

Currently, I am working on a form that allows users to create a product. This form is equipped with react-hook-form to efficiently manage all the inputs. I am considering reusing this form for the Edit page since it shares the same fields, but the data wil ...

Utilize an array of JSON objects to populate an array of interfaces in Angular/Typescript

I am currently facing a dilemma - my code is functioning without any errors when executed, but my text editor is flagging an issue stating that the property 'categories' does not exist on type 'CategoryInterface[]' (specifically on the ...

How to anticipate an error being thrown by an observable in RxJS

Within my TypeScript application, there exists a method that produces an rxjs Observable. Under certain conditions, this method may use the throwError function: import { throwError } from 'rxjs'; // ... getSomeData(inputValue): Observable<s ...

What is the method to prevent the label from closing in the MUI 5 datepicker?

Is there a method to prevent the Material 5 Datepicker from closing when there's a label but no value? Current Scenario: Current Desired Outcome: Expected Sample Code: <LocalizationProvider dateAdapter={AdapterDayjs}> <DatePicker lab ...

Exploring an array in Angular 2 using TypeScript

Just starting out with typescript and angular2 and working through some issues. I have a form that needs to display results from an array of changing items, so I don't know the exact index of each result. Here is my scenario: In my form.html file: ...

What is the recommended way to handle data upon retrieval from a Trino database?

My goal is to retrieve data from a Trino database. Upon sending my initial query to the database, I receive a NextURI. Subsequently, in a while loop, I check the NextURI to obtain portions of the data until the Trino connection completes sending the entire ...

Unraveling TypeScript code expressions

I am seeking clarification on the meaning and practical application of this particular expression. ((identifier:string) => myFunction(identifier))('Hi') myFunction const myFunction = (str:string) => { console.log(str) } The output displ ...

Tips for successfully passing a closure as a parameter in a constructor

I encountered an issue while working with a third-party library where I needed to register my own control. The problem arose when I tried to add another dependency to the control and struggled with passing a closure as a parameter to fulfill the required c ...

Guide to implementing ion-toggle for notifications with Ionic 2 and Angular 2

Currently, I am using a toggle icon to set the notification as active or inactive. The response is obtained from a GET call. In the GET call, the notification value is either 0 or 1, but in my TypeScript file, I am using noteValue as boolean, which means w ...

I'm having trouble inputting text into my applications using React.js and TypeScript

I am encountering an issue where I am unable to enter text in the input fields even though my code seems correct. Can anyone help me figure out what might be causing this problem? Below is the code snippet that I am referring to: const Login: SFC<LoginP ...

How come a null variable continues to widen to type any even when strictNullChecks is enabled?

According to the TypeScript Documentation, if strictNullChecks is true, there should be no type widening. Also, the typeof nul should be null. let nul = null; // typeof nul = any let undef = undefined; // typeof undef = any Check it out in the Playground ...

Utilizing formData.append in TypeScript to handle arrays

Hey there! I'm facing an issue while trying to send a form to my Profile endpoint. The problem lies in the 'user:{}' field, as I am unable to properly insert my array data into this specific field. Here is a breakdown of the fields within m ...

Ngrx effects are not compatible with earlier versions of TypeScript, causing issues with functionality

Seeking assistance with my Ionic 3 App utilizing ngrx/store and ngrx/effects. However, upon attempting to run the app, I consistently encounter the following error: TypeScript Error A computed property name in a type literal must directly refer to a bui ...

How to show table cell value in Angular 4 using condition-based logic

I am a beginner in Angular development. Here is the HTML code I am working with: <tr *ngFor="let item of calendarTableSelected; let idx = index"> <span *ngIf="idx === 0"> <td style="width:15%;" *ngFor="let name of item.results" ...

Exploring ways to display all filtered chips in Angular

As a new developer working on an existing codebase, my current task involves displaying all the chips inside a card when a specific chip is selected from the Chip List. However, I'm struggling to modify the code to achieve this functionality. Any help ...

The property 'supabaseUrl' cannot be destructured from 'getConfig(...)' because it is not defined

I recently went through the tutorial provided by @supabase/auth-helpers-sveltekit on integrating supabase-auth helpers with sveltekit. However, upon running the development server, I encountered an internal error. Cannot destructure property 'supabas ...

Creating an extended class in Typescript with a unique method that overrides another method with different argument types

I need to change the argument types of a method by overriding it: class Base { public myMethod(myString: string): undefined { return; } } class Child extends Base { public myMethod(myNumber: number): undefined { return super.m ...

Understanding the mechanism behind how the import statement knows to navigate to the package.json file

I find myself stuck in bed at the moment, and despite numerous Google searches with no clear answers, I have chosen to seek help here. Could someone please clarify how scoping works when using import in TypeScript and determining whether to check the pack ...

Customize TypeScript Generic Types in Method<T> Extending from a Base Class<T> as a Backup Plan

In my example, I have created an Angular Service with multiple Generic Types that can be overridden through the methods. The issue I am encountering revolves around = versus extends and how it affects typing in the arguments. Strangely, using = works perfe ...