What is the process of assigning a value type to a generic key type of an object in typescript?

I am currently working on developing a function that can merge and sort pre-sorted arrays into one single sorted array. This function takes an array of arrays containing objects, along with a specified key for comparison purposes. It is important to ensure that the value corresponding to the provided key is always numeric.

Here's the progress I have made so far:

const sortMerge = <
  A extends Array<I>,
  K extends keyof A[number],
  I = A[number] & {
    [key in K]: number;
  },
>(
  arrays: A[],
  key: K,
  sortMethod = SortMethod.asc,
) => {
  const indexesOfArrays = arrays.map(() => 0);

  const mergedSorted = [];

  while (arrays.some((array, i) => array.length > indexesOfArrays[i])) {
    const currentItemsOfArrays = arrays.map(
      (array, arrayIndex) => array[indexesOfArrays[arrayIndex]],
    );
    const comparison = currentItemsOfArrays.map((item) =>
      item ? item[key] : (sortMethod === SortMethod.asc ? Infinity : -Infinity),
    );

    const nextArrayIndex = comparison.indexOf(
      Math[sortMethod === SortMethod.asc ? 'min' : 'max'](...comparison),
    );
    const nextItem = currentItemsOfArrays[nextArrayIndex];

    mergedSorted.push(nextItem);
    indexesOfArrays[nextArrayIndex]++;
  }
  return mergedSorted;
};

While everything seems to be working fine, there is an issue with recognizing I[K] as a numeric type, even though I attempted to define both K and I as generics.

Could you please point out what I may be doing incorrectly?

Anticipated errors/types:

const missingKey = [ { a: 1 } ];
const valid = [ { a: 2, b: 3 } ];
const anotherValid = [ { c: 3, b: 4 } ];

sortMerge([missingKey, valid], 'b') // missingKey[number] is missing property 'b';
sortMerge([valid, anotherValid], 'b') // expected return type: ({ a: number, b: number } | { c: number, b: number })[]

Answer №1

I made some adjustments to the generic constraints:

enum SortOrder {
  asc = 'asc',
}
const mergeSort = <
  Key extends PropertyKey,
  Element1 extends Record<Key, number>,
  Element2 extends Record<Key, number>,

  Array1 extends Element1[],
  Array2 extends Element2[],
  Arrays extends [Array1, Array2]
>(
  arrays: [...Arrays],
  key: Key,
  sortOrder = SortOrder.asc,
): (Arrays[number][number])[] => {
  const arrayIndexes = arrays.map(() => 0);

  const result = [];

  while (arrays.some((array, i) => array.length > arrayIndexes[i])) {
    const currentItems = arrays.map(
      (array, arrayIndex) => array[arrayIndexes[arrayIndex]],
    );
    const comparison = currentItems.map((item) =>
      item ? item[key] : (sortOrder === SortOrder.asc ? Infinity : -Infinity),
    );

    const nextArrayIndex = comparison.indexOf(
      Math[sortOrder === SortOrder.asc ? 'min' : 'max'](...comparison),
    );
    const nextItem = currentItems[nextArrayIndex];

    result.push(nextItem);
    arrayIndexes[nextArrayIndex]++;
  }
  return result;
}

const missingFields = [{ a: 1 }];
const validData = [{ a: 2, b: 3 }];
const anotherValidData = [{ c: 3, b: 4 }];

mergeSort([missingFields, validData], 'b') // missingFields[number] is missing property 'b';
const output = mergeSort([validData, anotherValidData], 'b')

Playground

If you need to infer keys of nested objects or objects in an array, it's best to start from the innermost level.

Key - inferred property of an object

Element - inferred object where keys are Key

Arr - inferred array of Element

Arrays - inferred array of Array

You may have noticed that I began by inferring the bottom-level properties and worked my way up through the arguments.

If you're interested in type inference in function arguments, you can read my article

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

Does Angular 2/4 actually distinguish between cases?

I have a question about Angular and its case sensitivity. I encountered an issue with my code recently where using ngfor instead of ngFor caused it to not work properly. After fixing this, everything functioned as expected. Another discrepancy I noticed w ...

Angular 2 GET request returns a 404 error

I have been attempting to reproduce the ngPrime datatable demo from this Github repository. Currently, I am working with the most recent version of Angular (4) and using angular-cli in development mode. Placing a JSON file into my app folder where the serv ...

Calling the `firstValueFrom()` method in RxJS will keep the observable alive and not

Hey there, I'm currently having issues with using firstValueFrom(), lastValueForm(), and Observable.pipe(take(1)) in my TypeScript code with Angular 14 and RxJs 7.8.0. I am working with a Firebase server that provides stored image URLs via an API wit ...

Moving the starting directory of a NodeJS application on Azure

My NodeJS app on Azure was initially written in Javascript with the app.js file located in the root directory. This file was automatically detected during deployment via Git. Recently, I converted the app to Typescript and now have a build directory, with ...

The user authentication service indicates that no user is currently logged in

Currently, I am working on implementing a route guard to distinguish between authenticated users and guests. In order to achieve this, I have created an auth-guard service along with an auth service. Although the user data is successfully stored in the loc ...

Using a parameter as a key index in JavaScript

Here's the structure of my Object festivals: Object {friday: Object} friday: Object amazon: Object band: Object Next, I've created a function called`newAct`: function newAct(band, date, startTime, endTime, stage){ var ...

How to determine the champion in a game of tic tac toe with the help of Redux and React in

As a beginner in react and redux, I am currently self-studying the concepts. States in my tic-tac-toe project are managed using redux. My goal is to determine the winner when X or O are aligned on the board. Below is my code: // store.ts import { co ...

Obtain the maximum or minimum value from an associative array using a function and provided parameters

Here is the code I have so far: <!DOCTYPE html> <html> <body> <button onclick="scanarray('a', 'max')">Test with a, max</button> <button onclick="scanarray('b', 'min')">Test with ...

Exploring the benefits of leveraging TypeScript with AWS NodeJS for improved stacktrace visibility over traditional JavaScript

I'm contemplating the idea of transitioning my existing JavaScript codebase to incorporate TypeScript in NodeJS. One aspect that I am concerned about is being able to view the stack trace in AWS CloudWatch (request log) in case an error occurs during ...

Exploring ways to display a JavaScript object on click from a .json file

As I delve into the world of javascript and json, I find myself facing a challenge. I am looking to extract information (using the Get Information function) from a json file within a javascript function triggered by an event. The catch is, I want to accom ...

Troubleshooting issue with problemMatcher in VSCode TypeScript compiler not functioning

I am looking for a problem matcher that can detect two types of issues: compilation problems related to TypeScript issues flagged by tslint This feature seems to be causing trouble in one of my projects, although it functions properly in others. Below i ...

Determine the total number of values that result from dividing the elements of the array

Suppose you are given an array containing N positive integers and a threshold value K. The goal is to divide each element of the array by K and count the number of resulting numbers. Calculate the sum of the counts for all array elements. Input: N = 4, K ...

How to increase a bytearray in Python 3?

What is the best way to increment a 16-byte array in Python 3, from 0x00000000000000000000000000000000 to 0x00000000000000000000000000000001? import base64 import Crypto from Crypto.Cipher import AES def incr(): k = b'\x01\x00\x0 ...

Encountering a TypeError when using Webpack and ts-loader to bundle a third-party library

While everything compiles and bundles successfully, a TypeError is encountered in the browser: "box2dweb_commonjs_1.default is undefined." No errors occur when starting webpack-dev-server and reviewing the bundle at http://localhost:8080/webpack-dev-serv ...

Error: Import statement cannot be used outside a module (@cucumber/cucumber) while using Node.JS, Playwright, and Cucumber framework

I encountered an issue while attempting to compile my Node.js code that is compliant with ECMAScript 6: $ npx cucumber-js --require features/step_definitions/steps.ts --exit import { Before, Given, When, Then } from "@cucumber/cucumber"; ^^^^^^ ...

An array containing multiple arrays in JSon format

I am currently working on creating a JSon document along with its corresponding xsd file to generate JAXB classes, and I'm not entirely sure if I am doing it correctly. The structure I aim to achieve is as follows: team -name="name" -game="game ...

Identifying memory leaks caused by rxjs in Angular applications

Is there a specific tool or technique available to identify observables and subscriptions that have been left behind or are still active? I recently encountered a significant memory leak caused by components not being unsubscribed properly. I came across ...

Guidelines for segregating a Union from an Array

I'm currently utilizing graphql-code-generator to automatically generate TypeScript definitions from my GraphQL queries. I have a specific union within an array that I am trying to extract in TypeScript. Is this feasible? Although I came across an exa ...

Error: Unable to parse string in URI within vscode API

Console LOG displays: \Users\skhan\Library\Application Support\Code\User\summary.txt The loop is used to replace the slashes. It works fine in Windows but not in Ubuntu and Mac. This is an example on OSX 10.11.6. Howev ...

The 'data' property is absent in the 'never[]' type, whereas it is necessary in the type of product data

Hello, I am new to TypeScript and I'm struggling with fixing this error message: Property 'data' is missing in type 'never[]' but required in type '{ data: { products: []; }; }'. Here is my code snippet: let medias :[] ...