Creating a function in Typescript that transforms an array into a typed object

Recently, I have started learning TypeScript and I am working on a function to convert arrays from a web request response into objects. I have successfully written the function along with a passing unit test:

import { parseDataToObject } from './ParseResults';

interface ITestPerson {
  name: string;
  age: number;
}

describe('parseDataToObject', () => {
  // Test cases omitted for simplicity

  describe('passed data and keys array', () => {
    it('returns an array of converted objects matching an interface', () => {
      const testData = [['matt', 25], ['dom', 45]];
      const testKeys = ['name', 'age'];
      const expectToBe: Array<ITestPerson> = [{ name: 'matt', age: 25 }, { name: 'dom', age: 45 }];
      expect(parseDataToObject<ITestPerson>({ data: testData, keys: testKeys })).toStrictEqual(expectToBe);
    });
  });
});

Here is the function that I have implemented:

export function parseDataToObject<T>({ data, keys }: {data: any[][], keys: Array<string>}): Array<T> {
  if (data.length === 0) return [];
  if (data[0].length !== keys.length) throw new Error("Keys array length doesn't match the data count");
  return data.map((dataArr: Array<any>): T => {
    let object = {};
    for (let i = 0; i < keys.length; i++) {
      object[keys[i]] = dataArr[i];
    }
    return object;
  });
}
// The above code resides in ParseResults.ts

Even though the function works fine in jest tests, I'm encountering some TypeScript compilation errors related to type handling.

The main objective is to convert an array of arrays into typed objects. An example of the API response data structure I am dealing with looks like this:

[[1622073600000,"39241.92000000","40411.14000000","37134.27000000","38529.98000000","86547.15879400",1622159999999,"3361413526.05354346",2102182,"42256.01280100","1641681553.52913720","0"],...]

After successful testing, when I try to implement it in my application as shown below:

// Binance.ts
export interface IKlineData {
  openTime: number;
  open: string;
  high: string;
  low: string
  close: string;
  volume: string;
  closeTiime: number;
  quoteAssetVol: string;
  numTrades: number;
  takerBuyBaseAssetVol: string;
  takerBuyQuoteAssetVol: string;
  ignore: string;
}
const klineDataKeys = [
  'openTime',
  'open',
  'high',
  'low',
  'close',
  'volume',
  'closeTiime',
  'quoteAssetVol',
  'numTrades',
  'takerBuyBaseAssetVol',
  'takerBuyQuoteAssetVol',
  'ignore'];


const result = await axiosGet(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=1d`);
// Line 68 
const klineData: Array<IKlineData> = parseDataToObject<IKlineData>({data: result.data, keys: klineDataKeys});

Unfortunately, TypeScript compiler throws a few errors as follows:

src/index.d/Binance.ts(68,75): error TS2322: Type 'unknown' is not assignable to ty
pe 'any[][]'.
src/index.d/binance.d/ParseResults.ts(7,7): error TS7053: Element implicitly has an
 'any' type because expression of type 'string' can't be used to index type '{}'.
  No index signature with a parameter of type 'string' was found on type '{}'.
src/index.d/binance.d/ParseResults.ts(9,5): error TS2322: Type '{}' is not assignab
le to type 'T'.
  'T' could be instantiated with an arbitrary type which could be unrelated to '{}'

I understand that there might be some unsafe operations within the parseDataToObject function, but I'm unsure how to rectify these issues. Any help would be greatly appreciated.

Below is a minimal reproducible example for reference:

import axios, { AxiosRequestConfig } from 'axios';

export interface IResponseData<T> {
  status: number;
  data: T;
}

export interface IKlineData {
  openTime: number;
  open: string;
  high: string;
  low: string
  close: string;
  volume: string;
  closeTiime: number;
  quoteAssetVol: string;
  numTrades: number;
  takerBuyBaseAssetVol: string;
  takerBuyQuoteAssetVol: string;
  ignore: string;
}
const klineDataKeys = [
  'openTime',
  'open',
  'high',
  'low',
  'close',
  'volume',
  'closeTiime',
  'quoteAssetVol',
  'numTrades',
  'takerBuyBaseAssetVol',
  'takerBuyQuoteAssetVol',
  'ignore'];

function axiosGet<T>(url: string): Promise<IResponseData<T>> {
  const axiosConfig: AxiosRequestConfig = {
    method: 'get',
    url,
    headers: {
      'Content-Type': 'application/json',
    },
  };

  return new Promise<IResponseData<T>>((resolve, reject) => axios(axiosConfig)
    .then((response) => {
      resolve({ data: response.data, status: response.status });
    })
    .catch((error) => {
      reject(error);
    }));
}

(async function () {
    const result = await axiosGet(`https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1d`);
    const klineData: Array<IKlineData> = parseDataToObject<IKlineData>({data: result.data, keys: klineDataKeys});
}());


function parseDataToObject<T>({ data, keys }: {data: any[][], keys: Array<string>}): Array<T> {
  if (data.length === 0) return [];
  if (data[0].length !== keys.length) throw new Error("Keys array length doesn't match the data count");
  return data.map((dataArr: Array<any>): T => {
    let object = {};
    for (let i = 0; i < keys.length; i++) {
      object[keys[i]] = dataArr[i];
    }
    return <T>object;
  });
}

Answer №1

Thanks to the assistance from @jcalz and a bit of additional troubleshooting on my end, I successfully resolved the issue and got it to compile. It was necessary for me to specify the generic type when calling the axios get function:

const response = await axiosGet<any[][]>(`https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1d`);

Furthermore, I had to provide explicit typing for the object where I dynamically define its properties as strings:

let obj: {[key: string]: any} = {};

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 error message states that the property 'registerUser' is not found on the class 'UserController'

In the controller file, I exported two functions (registerUser and loginUser) as default. No errors were thrown at that stage, but when attempting to access the routes, an error occurred stating - Property 'registerUser' does not exist on type &a ...

Verifying the presence of an object in an array based on its value using TypeScript

Having the following dataset: roles = [ {roleId: "69801", role: "ADMIN"} {roleId: "69806", role: "SUPER_ADMIN"} {roleId: "69805", role: "RB"} {roleId: "69804", role: "PILOTE"} {roleId: "69808", role: "VENDEUR"} {roleId: "69807", role: "SUPER_RB"} ] The o ...

What is the best way to make the current tab stand out?

I have implemented a TabHeader component to create a dynamic Tab Menu that displays table contents based on months. The loop runs from the current month back to January, and the content is updated dynamically through an API call triggered by changes in the ...

Resolve the issue with automatically generating SCSS type definitions (style.d.ts) for Preact within a TypeScript webpack setup

Utilizing webpack with Preact 10.x (nearly identical to React) and TypeScript in the VSCode environment. Following an update from Node version 12 to version 14, there seems to be a problem where *.scss files no longer automatically generate their correspo ...

Having trouble pinpointing the specific custom exception type when using the throw statement in TypeScript?

I have run into a problem while using a customized HttpException class in TypeScript. Let me show you how the class is structured: class HttpException extends Error { public status: number | undefined; public message: string; public data: any; ...

Looking for help with setting up Nodemailer and installing it via NPM

I am currently developing a mobile application using Ionic with Angular/Typescript, and I'm in need of a front-end solution to dynamically send emails in the background to a specific email address. I tried using emailjs, but it requires JavaScript whi ...

Navigating resolvedUrl with getServerSideProps in the newest version of NextJS - a comprehensive guide

Is there a way to obtain the pathname without using client-side rendering? I have been searching for information on how to utilize the getServerSideProps function, but so far with no luck. Initially, I attempted to employ usePathname; however, this result ...

Using ngFor to display a default image

My latest project involved creating a table that displays various products along with their corresponding images. Everything was working smoothly until I encountered an issue. In instances where a product is created without an associated image, I decided ...

Combining Vue2 with Typescript can sometimes result in a missing field in an object when assigning a Prop to

If I am using TypeScript version 4.1 and have a component structured like this. @Component export default class Test extends Vue { @Prop() private msg!: string; private testObj={ msg: this.msg, test: 123 } created(){ console.log(JSON. ...

Troubleshooting issue with alignment in Material UI using Typescript

<Grid item xs={12} align="center"> is causing an issue for me No overload matches this call. Overload 1 of 2, '(props: { component: ElementType<any>; } & Partial<Record<Breakpoint, boolean | GridSize>> & { ...

You cannot use Angular 5 to send a post request with a token that has been retrieved

Hello, I'm facing an issue with making a post request in Angular 5. The token I retrieve seems correct as it works fine when tested with Postman. Can someone provide me with a hint or suggestion on what could be going wrong? AuthService.ts getProfi ...

The Electron/React/Typescript module is missing: Error: Unable to locate 'fs' in the /node_modules/electron directory

Within my Electron application, I have a file named App.ts. It contains the following code snippet: import { ipcRenderer } from 'electron'; // remaining code However, during the app development process, I encountered this error message: Error: ...

Tips for showing nested array values in Angular 8

I'm new to using angular and I'm attempting to display values from an array within another array in a table format. Here is my JSON array that I'd like to display in rows: { "data": { "Influencer": [ { ...

Updating an item in the redux state is triggering a never-ending loop, leading to a browser

EXPECTED OUTCOME: My goal is to modify a value in my redux state ISSUE: I am encountering an issue where there is an infinite loop or the browser gets locked down. Despite consulting this Stack Overflow post and the official documentation, I am struggling ...

Issue with hydration in Next.js while trying to access the persisted "token" variable in Zustand and triggering a loading spinner

Below is the code snippet from _app.tsx where components/pages are wrapped in a PageWrapper component that handles displaying a loading spinner. export default function App(props: MyAppProps) { const updateJWT = useJWTStore((state) => state.setJWT); ...

What causes the error message "No exported member 'ɵɵFactoryDeclaration' in @angular/core/core" to appear during project compilation?

I am facing an issue where the global Angular CLI version is 13.0.1 and the local version in my project is 10.2.3. Despite making changes to some components (without touching package.json), I encountered an error during the build step of my bitbucket pipel ...

What is the best way to extract a specific value from a JSON object?

I'm currently working on building a marketplace using Angular. The main marketplace page is already set up and populated with data from a remote JSON file created with mockapi. However, I've encountered an issue when trying to display a single ra ...

What is the best way to implement a hover delay for an element in Angular?

Here is an element I'm working with: <div (mouseenter)="enter()" (mouseleave)="leave()">Title</div> In my TypeScript file: onHover = false; enter() { this.onHover = true; // additional functionality... } leav ...

"Is there a way to extract a value from a JSON object using

I have an object with the following key-value pairs: { 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': '918312asdasc812', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Login1&a ...

Common protocols: mypy error - The first argument does not have a compatible type ...; expected

I have been working on implementing a generic Protocol. My goal is to define a Widget[key_type, value_type] protocol with a simple getter method. When I used Protocol[K, T], Mypy raised an error so I switched to using Protocol[K_co, T_co]. Despite removing ...