Can we obtain the index of an item within an array while defining a type in TypeScript?

I am currently working on a function called createCells that takes an array of strings and generates an object with properties based on the index of each item in the array.

For instance, calling createCells(['10', '12', '13']) will produce an object with properties {Cell0, Cell1, Cell2}.

Up to this point, I have managed to create a version of the function where the object's properties are determined by the values in the array.

const createCells = <T extends `${number}`[]>(
    args: T,
) => {
    return args.reduce(
        (prev, curr) => ({
            ...prev,
            [`Cell${curr}`]: () => { },
        }),
        {}
    ) as {
            [key in typeof args[number] as `Cell${key}`]: (
            ) => void;
        };
};

However, using this implementation, the function createCells(['10', '12', '13']) would result in an object with properties {Cell10, Cell12, Cell13}.

To achieve my desired outcome, the function should be modified as follows:

const createCells = <T extends `${number}`[]>(
    args: T,
) => {
    return args.reduce(
        (prev, _curr, index) => ({
            ...prev,
            [`Cell${index}`]: () => { },
        }),
        {}
    ) 
};

My question is how can I use TypeScript to specify the type of the object returned by this function?

Answer №1

// Determining the length of a tuple allows the creation of a counter
type Increment<T extends unknown[]> = [...T, unknown]

// Defining a helper type to perform actions based on value and index
type CellType<CellValue, Index extends unknown[]> = { [K in `Cell${Index["length"]}`]: CellValue } // Actions based on value or index

// Loop through the tuple and intersect the result of CellType<~,~> to generate the target object
type CreateCells<T extends unknown[], Index extends unknown[] = []> =
    T extends [infer Head, ...infer Rest]
    ? CellType<Head, Index> & CreateCells<Rest, Increment<Index>>
    : {}

infer exact value typescript

// This type infers the value without using required and beautifies the intersection {a:"a"} & {b:"b"} => {a:"a", b:"b"}
export type Narrowable = string | number | bigint | boolean;
export type Narrow<A> =
    | (A extends Narrowable ? A : never)
    | (A extends [] ? [] : never)
    | {
        [K in keyof A]: A[K] extends Function ? A[K] : Narrow<A[K]>;
    };

const createCells = <T extends `${number}`[]>(
    // Using Narrow to prevent widening
    args: Narrow<T>,
): Narrow<CreateCells<T>> => {
    // Casting the argument is necessary for narrow 
    return (args as unknown as string[]).reduce(
        (prev, curr, index) => ({
            ...prev,
            [`Cell${index}`]: () => { },
        }),
        // Using any here just to satisfy the TypeScript compiler
        // It is a common practice when dynamically creating an object
        {} as any
    )
};

type Test = Narrow<CreateCells["1", "3"]>

const x = createCells(["1", "2", "3", "124214"]) //{ Cell0: "1"; Cell1: "2"; Cell2: "3"; Cell3: "124214";}
const z = createCells(["1", "2", "3", "124214asd"]) //invalid

playground

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

Tips for monitoring changes to files while developing a NestJs application within a Docker container

Having an issue with NestJS and Docker here. Trying to run the development script using npm start: dev, but encountering a problem where the app runs fine but doesn't detect any changes in the source files, hindering the development process. Here&apo ...

The error message "NgFor only supports binding to Iterables such as Arrays" is triggered even though the JSON response is formatted as an array

Using TypeScript in CompanyComponent Class export class CompanyComponent { apiService : APIService; data : any; private companyUrl = 'http://localhost:4000/api/company/'; constructor(apiService : APIService) { this.apiService = api ...

Modifying SASS variable within an Angular 2 TypeScript project

How can I update the Sass color variable based on user input in Angular 2? I came across a helpful resource, but it doesn't include any examples specifically for Angular 2. Any assistance would be greatly appreciated. Thank you! ...

What sets apart the commands npm install --force and npm install --legacy-peer-deps from each other?

I'm encountering an issue while trying to set up node_modules for a project using npm install. Unfortunately, the process is failing. Error Log: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolv ...

JavaScript: ES6 string method 'repeat' not recognized

Scenario: My environment consists of Windows 10, TypeScript 1.8, and Visual Studio Code 1.0.0. I have the following code snippet: ///<reference path = "./typings/lib.es6.d.ts" /> and later on, let z = "0".repeat(4 - str.length) This is where the ...

I'm feeling lost when it comes to rendering these components using styled-components in reactjs

Include the BarItem and BarItemSelect components inside the link when the condition is true, both styled with a specific CSS class. Currently, these are two separate components... I'm unsure how to achieve this const S = { BarItem: styled.a` pos ...

Tips for troubleshooting TypeScript Express application in Visual Studio Code

Recently, I attempted to troubleshoot the TypeScript Express App located at https://github.com/schul-cloud/node-notification-service/ using Visual Studio Code. Within the launch.json file, I included the following configuration: { "name": "notifi ...

The primary text is getting truncated when an ion-note is placed inside an ion-list

I'm currently working with Ionic 3 and attempting to create a list of events where the event name appears on the left and the event note (start time) appears on the right using an ion-note. Below is the code snippet: <ion-list *ngIf="events.len ...

What is the proper way to utilize a service within a parent component?

I need assistance with setting up inheritance between Child and Parent components. I am looking to utilize a service in the Parent component, but I have encountered an issue. When attempting to input the service in the Parent constructor like this: expor ...

Error encountered in TypeScript when attempting to combine type string, number, or null, but not when combining only string or

What causes the function foo to display an error message Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. at the return value; line while the function bar f ...

Error encountered in Angular 7.2.0: Attempting to assign a value of type 'string' to a variable of type 'RunGuardsAndResolvers' is not allowed

Encountering an issue with Angular compiler-cli v.7.2.0: Error message: Types of property 'runGuardsAndResolvers' are incompatible. Type 'string' is not assignable to type 'RunGuardsAndResolvers' This error occurs when try ...

When trying to access the "form" property of a form ElementRef, TypeScript throws an error

I've encountered an issue with accessing the validity of a form in my template: <form #heroForm="ngForm" (ngSubmit)="onSubmit()"> After adding it as a ViewChild in the controller: @ViewChild('heroForm') heroForm: ElementRef; Trying ...

Utilizing an Angular Service within the main.ts script

My main.ts file currently has the following code snippet: declare const require; const translations = require("raw-loader!./locale/messages.de.xlf"); platformBrowserDynamic().bootstrapModule(AppModule, { providers: [ { provide: TRANSLATIONS, useVa ...

Issue: NG04002 encountered post migration from Angular to Angular Universal

Having recently created a new Angular app and converted it to Angular Universal, I encountered an issue when running the project using npm run dev:ssr. The error displayed in the terminal is as follows: ERROR Error: Uncaught (in promise): Error: NG04002 Er ...

Personalized style for text overflow property

The application is created using Angular. Within a component, we have a div containing some text: <div>abcdefghijklmnop<div> Depending on the screen size, the text should either be fully displayed or clipped. I discovered the property 'te ...

Are there any APIs available for creating TypeScript reflection programmatically?

My goal is to extract metadata associated with Props objects. For instance, the output I am looking for could be as simple as: { suffix: 'string', count: 'number', increment: 'function' } I understand that this task ca ...

Having trouble with vscode compiling the typescript file?

Even though I diligently followed the tutorial provided by vscode on compiling typescript code, I encountered a problem. The configurations were set up as per the instructions in the tutorial, but when I tried to run the code without debugging, I received ...

Unable to access component properties through react-redux

Context: A React Native application utilizing Redux for managing complexity. Versions: typescript v3.0.3 react-native v0.56.0 redux v4.0.0 @types/react-redux v6.0.9 @types/redux v3.6.0 Issue: The main JSX component in my app is unable to access proper ...

Retrieving the type of a mapped property using the TypeScript compiler API

If I have a type Mapping = Record<'success' | 'error', React.ReactNode>, how can I extract the TypeScript type using the compiler API? While the symbol for Mapping has the expected two properties, the symbol for each property doe ...

What are the recommended methods for ensuring compatibility of enums in Typescript?

I have a const enum named ComponentId with values A, B, and C. Additionally, there is another const enum called BaseId with values D, E, and F which is used in multiple places. const enum ComponentId { A = 0, B, C } The challenge I am facing ...