How can I cast a string to number in an response using axios?

Viewed 1183

I am using Axios to execute a GET request to a public API. This API return a numeric value as string. I need to cast this value a numeric value. My application runs using tsc, so I expect the result of my object to be a numeric value, but it's not.

Axios Response

[
  {
    "name": "foo1",
    "value": "8123.3000"
  },
  {
    "name": "foo2",
    "value": "5132.2003"
  },
  {
    "name": "foo3",
    "value": "622.0000"
  }
]

Expected Output

[
  {
    "name": "foo1",
    "value": 8123.3
  },
  {
    "name": "foo2",
    "value": 5132.2003
  },
  {
    "name": "foo3",
    "value": 622
  }
]

My code is very simple,

interface MyObj {
  myString: string;
  myNumber: number;
}

(async () => {
  let { data }: AxiosResponse<MyObj> = await axios.get<MyObj>("/public/data");
  console.log(data);
})();

I try to use interface, class, the interface Number. Nothing worked.

I leave an example of code to try it.

How can I get the expected output without manually converting each value one by one?

2 Answers

When declaring that your axios request returns a certain type; this will be checked at compile time and syntax checking. It does not however do this at runtime. If you know that the axios request is returning something different than your interface, you need to convert to that format first. You can do this using the second argument of the JSON.parse function like so:

interface Item {
  name: string;
  value: number;
}

let responseString = `
[
  {
    "name": "foo1",
    "value": "8123.3000"
  },
  {
    "name": "foo2",
    "value": "5132.2003"
  },
  {
    "name": "foo3",
    "value": "622.0000"
  }
]`

const items: Item[] = JSON.parse(responseString, (key, value) => {
  const propertiesToCast = ["value"] // Which properties should be converted from string to number
  if (propertiesToCast.includes(key)) {
    return parseFloat(value)
  }
  return value
});

console.log(items)

Axios does not change the type of properties in the response. Please verify that the server does not send you the wrong types.


Edit

From your comment, it seems that the server sends you the vslue as string instead of as number. In this case I would suggest working with Ajv (https://github.com/ajv-validator/ajv) so you can create a schema that describes how the response looks like. Ajv cn also transform the value from string to number for you:

const Ajv = require('ajv')

const ajv = new Ajv({
  // allow chaning the type of some values from type X to type Y. depends on the source and target type:
  // https://ajv.js.org/guide/modifying-data.html#coercing-data-types
  // X => Y rules: https://ajv.js.org/coercion.html
  coerceTypes: true,
})

const schema = {
  type: 'array',
  items: {
    type: 'object',
    properties: {
      name: { type: 'string' },
      value: { type: 'number' },
    },
    required: ['name', 'value'],
    additionalProperties: false,
  },
}

const data = { name: 1, value: '1.1' }

console.log(typeof data.value === 'number') // false!

const valid = ajv.validate(schema, data)
if (!valid) {
  console.log(ajv.errors)
  process.exit(1)
}

console.log(typeof data.value === 'number') // true!
Related