What is the data type returned by mapping an array in TypeScript?

I am working on a function that handles sorting columns

export const handleSortableColumns = (headerKeys: string[], sortKeys: object): string[] => {
  if (!headerKeys) return [];

  return headerKeys.map((key: string): any => sortKeys[key] || null);
};

The headerKeys parameter accepts a list of strings. The sortKeys parameter is supposed to be an object, but I'm not sure about specifying its type since the properties can be different each time. Should I use generics for this? How can I implement it? Also, the return type should be a list of strings including null values, so what would be the correct return type without using the any keyword?

Answer №1

To handle the sortKeys, one approach is as follows:

interface ISortKeys {
  [key: string]: string
}

When it comes to the output type, consider using

(string|null)[]

Answer №2

I made a crucial change by swapping the positions of sortKeys and headerKeys. This adjustment enhances user experience as the type checker can now easily identify the object you are working on. Additionally, I modified headerKeys to be variadic, but if you prefer, it can be reverted back to a standard array.

const handleSortableColumns = <T>(sortKeys: T, ...headerKeys: (keyof T & string)[]): (string | null)[] => {
    if (!headerKeys) return [];
    const result = headerKeys.map(key => sortKeys[key] || null);
    return result as (string | null)[];
}

.

handleSortableColumns({ a: '1', b: 2 }, 'a', 'X');

This now results in a type error. However, it does not prevent scenarios like:

handleSortableColumns({ a: '1', b: 2 }, 'a', 'b');

Introducing more stringent checks for return types can quickly lead to convoluted code. Instead, I suggest utilizing run time checks, such as filter or throw, for better readability and maintainability.

Answer №3

By utilizing generic type parameters, you can deduce the types of input values and then utilize these generics to generate an array return type that signifies the subset of values in the object accessible through indexing the values in the input array (or null). Here's a demonstration:

TS Playground

function handleSortableColumns <
  Keys extends readonly string[],
  ValueMap extends Record<string, unknown>,
>(headerKeys: Keys, valueMap: ValueMap): (ValueMap[Extract<keyof ValueMap, Keys[number]>] | null)[] {
  return headerKeys.map(
    key => (valueMap[key] ?? null) as ValueMap[Extract<keyof ValueMap, Keys[number]>] | null
  );
}

const keys = ['a', 'b', 'c'] as const;

const map = {
  a: 1,
  c: false,
  d: 'hello world',
};

const result = handleSortableColumns(keys, map);
    //^? const result: (number | boolean | null)[]

console.log(result); // [1, null, false]

Compiled JS from the TS Playground:

"use strict";
function handleSortableColumns(headerKeys, valueMap) {
    return headerKeys.map(key => (valueMap[key] ?? null));
}
const keys = ['a', 'b', 'c'];
const map = {
    a: 1,
    c: false,
    d: 'hello world',
};
const result = handleSortableColumns(keys, map);
//^?
console.log(result); // [1, null, false]

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 is the correct way to write SVG markup within SVG tags in a React and NextJS environment?

I currently have a Svg component set up like this interface SvgIconProps { children: React.ReactNode; strokeWidth?: number; width?: number; height?: number; className?: string; } export const SvgIcon = ({ children, strokeWidth = 1, width = ...

Concealing the sidebar in React with the help of Ant Design

I want to create a sidebar that can be hidden by clicking an icon in the navigation bar without using classes. Although I may be approaching this incorrectly, I prefer to keep it simple. The error message I encountered is: (property) collapsed: boolean ...

Leverage the exported data from Highcharts Editor to create a fresh React chart

I am currently working on implementing the following workflow Create a chart using the Highcharts Editor tool Export the JSON object from the Editor that represents the chart Utilize the exported JSON to render a new chart After creating a chart through ...

Angular index.html file can include a conditional script

I am currently working on an Angular project, where the index.html serves as the main entry point for the application, just like in any other Angular project. This file contains important links and configurations. Within the HTML code snippet below, you w ...

Using the index in Vue.js to locate a method within an HTML file

Currently, I am attempting to make use of the reference "index" located within <tr v-for="(note, index) in noteList" v-bind:key="index" in order to call shareToPublic(index). The method selectedID() allows for the selection of the ...

In Typescript, you can extend an interface with the Node type to specifically

I'm currently utilizing Cypress 10. I came across the following code snippet: Cypress.Commands.add( 'byTestId', // Taking the signature from cy.get <E extends Node = HTMLElement>( id: string, options?: Partial< ...

Can Typescript automatically determine the return type based on the function argument value?

How can Typescript be utilized to deduce the return type from the valueType parameter instead of using overloads? type ValueType = 'integer' | 'string' | 'number' | 'date' | 'dateTime' | 'boolean&apos ...

Familial Connection (TYPESCRIPT)

Is there a way to set the state in ISetOpen based on the type of modal in ISetOpen? For example: If ISetOpen.modal is 'payModal': Set ISetOpen.state to IPayModal If ISetOpen.modal is 'deleteModal': Set ISetOpen.state to IDeleteModal ...

Sorting orders using Firebase

Currently, I am developing an Ionic project and facing an issue with displaying firebase documents on the screen. My goal is to order these documents by date, which is a field of type date in each document within my collection: Below is the code snippet t ...

Supporting right-to-left (RTL) localization in Angular 2 and later versions

When it comes to incorporating right-to-left (RTL) support into a localized Angular 2+ application, particularly for languages like Hebrew and Arabic, what is considered the best approach? I have explored various tutorials, including Internationalization ...

Converting SASS in real-time using SystemJS

I have been reading various blogs discussing the use of SystemJS and SASS transpiling, but most of the examples I come across involve pre-processing SASS files before importing them into JavaScript code. However, I am interested in being able to directly i ...

Updating a Parent entity in Prisma with the option to also update its associated Child entity in a

I am currently managing a Parent Child (One-To-One) Relationship structured like this: model Account { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt billingAddress Address? name ...

Leveraging observables for loading fbx files in three.js

Currently, I am utilizing three.js to exhibit some 3D-meshes within the browser. However, I am facing a challenge where I need to execute a specific function only after certain elements have finished loading. While some models just require importing, other ...

Error in Angular integrating with Stripe. No definition found for 'Stripe'. Perhaps you meant 'stripe'?

I'm currently in the process of connecting Stripe to my app with redirection, utilizing Angular and typescript. My component contains the following code snippet: var head = document.getElementsByTagName('head')[0]; var script = document.cre ...

Applying ngClass to a row in an Angular material table

Is there a way I can utilize the select-option in an Angular select element to alter the css-class of a specific row within an Angular Material table? I have successfully implemented my selection functionality, where I am able to mark a planet as "selecte ...

Using *ngFor to dynamically update the DOM when an array is modified via ngrx

Currently, I am utilizing *ngFor to present values from an array: [ { id: 1, name: 'item1' }, { id: 2, name: 'item2' } ] In the html: <div *ngFor="let item of (items$ | async); trackBy: trackById;&quo ...

Incorporating TypeScript into an established Node.js Express project

I am keen on building a Node.js Express application using TypeScript. I have been watching several tutorials online to learn how to integrate TypeScript in Node.js, and fortunately, it is functioning as intended. However, the .ts files are currently bein ...

Navigate to a different directory within Cypress by utilizing the cy.exec() function

Dealing with cypress to execute a python script in another directory. However, it seems like the directory change is not functioning as expected. visitPythonProject() { cy.exec("cd /Users/**/Desktop/project/"); cy.exec("ls"); // thi ...

Where can the body of this function be located in Typescript and do the generics serve a practical purpose?

While perusing the documentation for Angular's "AsyncPipe", I found myself at a standstill on line 26, where the 'resolve' function is invoked: this.resolve !('hi there!'); I have some questions on my mind: (A) Where is the impl ...

Displaying a list in Angular 2/4 without keeping track of any modifications

Is there a way to display a list of strings without tracking changes? (I'm experiencing performance issues). Fetching a list of languages from a REST API and then dynamically generating dropdowns for each language using *ngFor is causing the app to s ...