1

I'm using an API that returns the following response:

[
  [ 1636765200000, 254.46, 248.07, 254.78, 248.05, 2074.9316693 ],
  [ 1636761600000, 251.14, 254.29, 255.73, 251.14, 5965.53873045 ],
  [ 1636758000000, 251.25, 251.15, 252.97, 249.78, 7803.5565834 ],
  ... more items
]

I use axios to make a request against it as follows:

let res = await axios.get<CandlesResponse[]>(`${baseUrl}/${pathParams}?${queryParams}`);
let {data} = res;

In this case, TS infers the following:

  • let res: AxiosResponse<CandlesResponse[], any>
  • let data: CandlesResponse[]

I'm having troubles understanding how to define the interface that gets mapped. I tried the following:

interface CandlesResponse {
    values:number[];
}

If I run, for example:

let lastCandle = data[119];
console.log(lastCandle.values)

in both cases, I got undefined as response.

While trying I managed to find something that works defining the Interface as follows:

interface CandlesResponse {
    0:[number, number, number, number, number, number];
    1:[number, number, number, number, number, number];
    2:[number, number, number, number, number, number];
    3:[number, number, number, number, number, number];
    4:[number, number, number, number, number, number];
    5:[number, number, number, number, number, number];
}

But I cannot understand why it works. I also found out (and this, to me, makes more sense since each CandlesResponse is an array of numbers) that it works also defining the interface like this:

interface CandlesResponse {
    0:number;
    1:number;
    2:number;
    3:number;
    4:number;
    5:number;
}

This allows me to get the values like this:

let lastCandle = data[119];
console.log(lastCandle[0])

obtaining 1636340400000.

I need to understand why does it work like this. In particular, why does it work in both ways:

  • 0:[number, number, number, number, number, number];
  • 0:number;

Why the values:number[]; approach returns undefined, instead?

Also I want to understand if there is the possibility to give a proper name, instead of an index, to access those values. I want something that looks like this:

interface CandlesResponse {
    MTS:number;
    OPEN:number;
    CLOSE:number;
    HIGH:number;
    LOW:number;
    VOLUME:number;
}

...

let lastCandle = data[119];
console.log(lastCandle.MTS);

I guess I'm a bit confused and I hope someone can help me understand the problem

EDIT: I can obtain the structure that I want by doing something as follows:

interface CandlesResponse {
    0:number;
    1:number;
    2:number;
    3:number;
    4:number;
    5:number;
}

class Candle{
    MTS:number;
    OPEN:number;
    CLOSE:number;
    HIGH:number;
    LOW:number;
    VOLUME:number;

    constructor(MTS: number, OPEN: number, CLOSE: number, HIGH: number, LOW: number, VOLUME: number){
        this.MTS = MTS;
        this.OPEN = OPEN;
        this.CLOSE = CLOSE;
        this.HIGH = HIGH;
        this.LOW = LOW;
        this.VOLUME = VOLUME;
    }
}

...

    let res = await axios.get<CandlesResponse[]>(`${baseUrl}/${pathParams}?${queryParams}`);
    let {data} = res;
    let candles:Candle[] = data.map(candle => new Candle(candle[0], candle[1], candle[2], candle[3], candle[4], candle[5]))
    console.log(candles[1].CLOSE)
    

Still I cant understand why it worked defining in the CandlesResponse interface the properties like this:

0:[number, number, number, number, number, number];

I also wonder if there is a better way to do it

SUMMARY:

I want to understand if there is a way to map the response object by giving proper names to access the fields (response is an array of arrays and I want o give to each internal array's value a proper name instead of an index). Also I would like to understand how does it work

3
  • Could you please summarize the questions at the end? BTW, I would recommend using [number, number, number, number, number][] as the type and using a JSDoc comment to annotate it. Commented Nov 13, 2021 at 3:18
  • @Shivam I did a brief summary of my question. So you suggest me to map the data in a matrix shape (which is fine).. Is there a way to give to each internal array a proper name? Or can I access it only by using the index? What I'm asking if I can do something like: data[0][MTS] instead of data[0][0] Commented Nov 13, 2021 at 11:56
  • 1
    If you want to give the indices a name, then you'll probably have to do a runtime mapping between an array and an object with fields. It's unfortunate, but it's rare enough that this would be a performance concern. Commented Nov 13, 2021 at 12:13

1 Answer 1

1

I think your issue is dealing with an interface that represents an array which basically has an auto incrementing key (or index).

If you create a dedicated type that represents a single Candle, and then use that to represent the shape of the response, it becomes a little easier. All you have to add is `[index: number]' to represent the index and it should work:

// Named this way to avoid clash with the existing Candle class
type CandleType = [number, number, number, number, number, number];

interface CandlesResponse {
    [key: number]: CandleType
}
Sign up to request clarification or add additional context in comments.

7 Comments

First of all thank you for your explanation: let res = await axios.get<CandlesResponse[]>( ${baseUrl}/${pathParams}?${queryParams} ); let { data } = res; console.log(data[1][0]) this allows me to access the data in a "matrix shape" (data[0][0]) and I think its great! I still can't understand also why this mapping ([key: number]) works. Is there a way, then, to give to every element of CandleType a name? For example to access it like this: data[0][MTT] ? Also can you explain me how the [key: number]: CandleType works?
Does [key: number]: CandleType means that i have a key that is a number (data[0]) that returns me a Candle Type which is an array of 5 numbers, right? I
Yes, so if you were to assign a string as the key instead of a number, you would do [key: string]. The key part is just the name, so you can call this whatever you like.
Ah ok I see. A small suggestion would be to have the CandlesResponse be responsible for the entire response rather than relying on having to define it as CandlesResponse[]. Elsewhere in your code you'll see CandlesResponse and think that is the actual response, whereas it is only one part of it. CandlesResponse[] to me says it's an array of responses.
I second that, so I chose this as implementation: interface CandleType { [key: number]: number; } type CandlesResponse = CandleType[]; And this keeps working as desired ! Thank you for your help!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.