An undefined type is implicitly being used in the transform operation

Having trouble with formatting this specific function:

function createConversion<TObj extends Record<string,any>, K extends keyof TObj>(converter: Record<K, (x:TObj[K])=>any>): (o:TObj)=>any {
    return (obj: TObj) => {
        const out: any = {...obj}
        for (const key of Object.keys(converter)) {
            out[key] = converter[key](obj[key])
        }
        return out;
    }
}

Example of usage:

const trans = createConversion({a:x => x*2});
const arr = [{a:1,b:2},{a:3,b:4}];
console.log(arr.map(trans)) // [ { a: 2, b: 2 }, { a: 6, b: 4 } ]

Error Encountered:

The issue is coming from the string type in Record<string,any>, but unsure about potential alternatives. It's supposed to exclusively accept string keys, while the converter should only have a subset of keys from TObj.

Answer №1

transformer requires a key k of type K (the generic type parameter), yet Object.keys only returns broad strings and causes a compilation error.

For potential solutions, refer to this response; using a type assertion is appropriate in this scenario.

Furthermore, an issue arises with the inference of type parameter TObj for the transformer within the outer function. This can be resolved by currying the inner function with the actual obj: TObj. Avoiding the use of any types is strongly encouraged to ensure better typing enforcement.

To address these concerns, we can redefine the typings based on the callback function of transformer within the makeTransform function. By making TObj a type parameter of the inner function that meets the constraints of the outer transformer, we eliminate any unnecessary type assertions and usage of any.

function makeTransform<
  T extends Record<string, (arg: any) => any>
>(transformer: T) {
  return <TObj extends { [P in keyof T]: Parameters<T[P]>[0] }>(obj: TObj) => {
    const objClone: Omit<TObj, keyof T> = { ...obj };
    // Type casting is necessary here to maintain correct typings
    const mapped = {} as { [P in keyof T]: ReturnType<T[P]> };

    for (const k of Object.keys(transformer)) {
      // Using a workaround for Object.keys typings
      const kC = k as keyof T;
      mapped[kC] = transformer[kC](obj[kC]);
    }
    return { ...objClone, ...mapped };
  };
}

Test it out:

const trans = makeTransform({
  a: (x: number) => String(x * 2),
  b: (x: string) => parseInt(x)
});

const res0 = [{ a: 1, b: "11" }, { a: 2, b: "22" }].map(trans);
const res1 = [{ a: 1, b: "11", c: new Date() }, { a: 2, b: "22", c: {} }].map(trans);
const res2 = [{ a: 1 }, { a: 2, b: "22" }].map(trans); // error: b not found (OK)
const res3 = [{ a: 1, b: "11" }, { b: "22" }].map(trans); // error: a not found (OK)
const res4 = [{ a: "1", b: "11" }, { a: 2, b: "22" }].map(trans); // error: 'a' incompatible (OK)
const res5 = [{ a: 1, b: "11" }, { a: 2, b: 22 }].map(trans); // error: 'b' incompatible (OK)

console.log(res0); // [{ a: "2", b: 11 }, { a:"4", b: 22 }]

Playground

Answer №2

Acknowledgment to contributor k48 (source: )

This particular approach is functional:

function createConverter<TObj extends Record<string, any>, K extends keyof TObj>(converter: Record<K, (x: TObj[K]) => any>): (obj: TObj) => any {
    return (inputObj: TObj) => {
      const outputObj: any = { ...inputObj }
        for (const key in converter) {
          outputObj[key] = converter[key](inputObj[key]);
        }
        return outputObj;
    }
}

const multiplyByTwo = createConverter({ a: x => x * 2 });

const dataArr = [{a:1,b:2},{a:3,b:4}];
console.log(dataArr.map(multiplyByTwo)) // [ { a: 2, b: 2 }, { a: 6, b: 4 } ]

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

combineLatest operates independently of an observable's emission timing

I am facing an issue with two services in my application. Each service has an observable, and I have a component that is supposed to get the last emitted value of both observables. However, I noticed that the combineLatest function fires as soon as one obs ...

Exploring Angular 10's advanced forms: delving into three levels of nested form groups combined with

Project Link: Click here to view the project In my testForm, I have 3 levels of formGroup, with the last formGroup being an array of formGroups. I am trying to enable the price field when a checkbox is clicked. I am unsure how to access the price contro ...

Testing with Jest and Jasmine in Typescript (tests successful, tslint errors)

My tests are passing successfully with jasmine (library tests) and jest (snapshot tests) thanks to including these lines at the top of my test files: /// <reference path="../../node_modules/@types/jasmine/index.d.ts" /> // -> in my jest test fil ...

How do I pass color values as props in React.Js using Typescript?

As a newcomer to React, I have encountered a component where colors were previously hard-coded. My goal is to pass a color through props instead. In addition, I am utilizing styledComponents for the styling, in case that affects anything. &[che ...

Incorrect positioning of AnyChart within a reusable component (Angular version 9.1.3, Bootstrap 4.4.1, Anychart version 8.7.1) causing display issues on the DOM

I have created a test dashboard featuring two Bootstrap cards, each containing an Anychart column chart. The primary objective is to experiment with reusable components. For those interested, here is the code link on Stackblitz Upon running the code, my ...

Prevent users from clicking buttons until all mandatory fields are filled out using react-hook-form

I am seeking guidance on how to dynamically disable a button based on the input values of both Name and State in the given code snippet. Specifically, I want to restrict button functionality until both name and state fields are filled out, regardless of ...

Can you explain the distinction between the controls and get methods used with the FormGroup object?

I have encountered an interesting issue with 2 lines of code that essentially achieve the same outcome: this.data.affiliateLinkUrl = this.bookLinkForm.controls['affiliateLinkUrl'].value; this.data.affiliateLinkUrl = this.bookLinkForm.get(' ...

Activating the microphone device on the MediaStream results in an echo of one's own voice

I am in the process of creating an Angular application that enables two users to have a video call using the Openvidu calling solution. As part of this application, I have implemented a feature that allows users to switch between different cameras or micr ...

What methods can be employed to maintain the integrity of tuple element labels?

Context In an attempt to enhance code readability and maintainability, I am exploring the replacement of a complex overloaded function with rest parameters using labeled tuple elements. Original snippet Here's a simplified version of the existing o ...

What is the best way to arrange the information in JSON in ascending order and display it in a table format?

I am working with a mat-table and have used GET to display my data. I now want to sort the data in ascending order based on the db-nr from my JSON. Here is an excerpt from my JSON: { "period": 12.0, " ...

My variable from subscribe is inaccessible to Angular2's NgIf

My goal is to display a spinner on my application while the data is being loaded. To achieve this, I set a variable named IsBusy to True before making the service call, and once the call is complete, I set IsBusy to false. However, I am facing an issue wh ...

The file located at 'node_modules/minimatch/dist/cjs/index' does not contain an exported element called 'IMinimatch'. Perhaps you intended to reference 'Minimatch' instead?

I encountered an error while using rimraf as a devDependency (v5.0.0) in my project. The error message I received was: node_modules/@types/glob/index.d.ts:29:42 - error TS2694: Namespace '".../node_modules/minimatch/dist/cjs/index"' has ...

Exploring the capabilities of the hardware camera in Angular 2

Struggling to implement the tutorial in Angular2. The challenge lies in making navigator.mediaDevices.getUserMedia function properly. The error message indicates that mediaDevices is not recognized on type 'navigator'. Refer to the media capture ...

"Transforming a callback function to an asynchronous function results in an error

I have a piece of code that is functioning as expected: var smtpConfig = { host: 'localhost', port: 465, secure: true, // use SSL selfSigned: true }; // create reusable transporter object using the default SMTP ...

Troubleshooting TypeScript Node.js Compilation Issue

In my quest to establish a debugging environment for a project from 2019, I included the following script in my package.json: "dev:debug": "tsc-watch --onFirstSuccess \"node --inspect -r ts-node/register src/app.ts\"", Executing this script pro ...

Utilizing client extension for Postgres with Prisma to activate RLS: A step-by-step guide

Recently, I attempted to implement client extension as advised on Github. My approach involved defining row level security policies in my migration.sql file: -- Enabling Row Level Security ALTER TABLE "User" ENABLE ROW LEVEL SECURITY; ALTER TABLE ...

Unleash the power of drag-and-drop functionality with cdkDrop

I am currently tackling a project that requires the implementation of a drop zone functionality where elements can be dragged from a list and dropped in a zone for free movement. I intend to utilize a cdkDropList for the zone due to its comprehensive list ...

Can one obtain a comprehensive array of interfaces or a detailed map showcasing all their variations?

I have developed a method that takes in an object containing data and returns an object that adheres to a specific interface. interface FireData { id: EventTypes; reason?: string; error?: string; } enum EventTypes { eventType1 = "ev1", ...

`Advancing Angular Bootstrap popover placement in response to varying circumstances`

As a complete novice in the world of Angular, I've done my fair share of research but still can't seem to find what I'm looking for. Here's a snippet of code that I'm working with: @Component({ selector: "help-icon", templateUrl: ...

How can I create an instance of a connected component in a Typescript React project?

This particular project consists of distinct components that are not closely related and should be shown side by side. As a result, I aim to configure the application in a way that allows each major component to query the Redux store independently. While t ...