skip to Main Content

I need to convert a query string into an object, but with the respective data types. Let me explain it better: I use a table from an external service that generates filters when I add them. I need to put these filters into a query string and then read them back. When I read them back, I need each type to return to its initial state. For example, if before putting the query in the query string I have { foo: 10 }, I need it to have the same thing when reading it back and not { foo: "10" }. However, we know that the query string is, in fact, a string, and when I convert it back, the values of the JSON attributes are still strings. I’m not asking you to create a method for me that does this, but I would like to know if you know of a simpler way, such as some utility.

I started writing this method:

const parseStringToJson = (str: string | null | undefined): object => {
  // str is skip=0&take=10
  const parsedJSON: any = QueryString.parse(str || {});
  // parsedJSON is { skip: "0", take: "10"}

  const convertDataType = (data: object | null): void => {
    Object.entries(data || {}).forEach(([key, value]) => {
      let isNumber = (typeof value === 'number' || (typeof value === 'string' && !isNaN(parseFloat(value))));
      let isBoolean = value === 'true' || value === 'false';
      //value is number
      if (isNumber) {
        return (parsedJSON[key] = Number(value));
      }
      //value is boolean
      if (isBoolean) {
        return (parsedJSON[key] = value === 'true');
      }
      //value is string
      if (typeof value === 'string' && !isNumber) {
        return (parsedJSON[key] = value);
      }
    });
  };

  convertDataType(parsedJSON);
  // parsedJSON is { skip: 0, take: 10}
  return parsedJSON;
};

Where QueryString is imported from qs

This works only with one level objects, but I need to do it deep inside. Also Manage arrays.

So before I starting doing that, Do you have a better idea to do so?

2

Answers


  1. let arr = ["one", "1", 1];
    
    arr.forEach(function(item){
    if(Number(item)){
    console.log("Item '" + item + "' converts to " + Number(item));
    } else {
    console.log("The argument '" + item + "' cannot be converted to a number");
    }
    });
    Login or Signup to reply.
  2. Your parsedJSON is not JSON (it’s already a plain object) and so what you’re asking seems to be a poorly phrased "how do I automatically convert strings to other datatypes if that’s what they are".

    Ironically, one of the answers here (if you don’t want to use a schema library, which you probably should) is to create an actual JSON string representation of your object, using a replacer function that converts values on the fly (because JSON.stringify is a tree-walker) and then parsing the result back from JSON to plain object:

    const someData = {
      cake: "yum",
      ingredients: {
        eggs: "3",
        oil: "false",
      },
      timings: ["short", "30", "short"]
    };
    
    function convert(key, value) {
      const type = typeof value;
      if (type === `string`) {
        const trimmed = value.trim();
        // for numbers, take advantage of type coercion:
        const num = parseFloat(trimmed);
        // note the intentional use of == instead of === here:
        if (trimmed == num) return num;
        // for booleans, just string compare:
        const lc = trimmed.toLowerCase();
        if (lc === `true`) return true;
        if (lc === `false`) return false;
      }
      // bonus feature: instead of crashing on functions, just ignore them!
      if (type === `function`) return;
      // Then let JSON.stringify deal with whatever's left.
      return value;
    }
    
    console.log(
      JSON.parse(
        JSON.stringify(someData, convert)
      )
    );

    Is this a good solution? No. Use a model/schema solution that can ingest string data and automatically convert it to the data type it should be. With model validation, so that if you’re trying to create an incomplete or incompatible model instance, you can catch that and do whatever you need to do on input failure.

    Is it a fun solution? Absolutely. Tree-walking an object using JSON.stringify is one of JS’s hidden bonus features.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search