1

I am making a method to convert querystring to object. The method works well, but typing is reporting an error.

https://jsfiddle.net/h723zuen/2/

const fromQueryString = <
  T extends {
    [x: string]: string | number | boolean | string[] | number[] | boolean[];
  }
>(
  querystring: string,
) => {
  const out: {
    [x: string]: string | number | boolean | string[] | number[] | boolean[];
  } = {};
  const arr = querystring.split('&');

  arr.forEach((a) => {
    const [key, value] = a.split('=');
    console.log(key, toValue(value), out, key in out);
    if (!!key && !!value) {
      if (key in out) {
        out[key] = Array.isArray(out[key])
          ? out[key].push(toValue(value))
          : [out[key], toValue(value)];
      } else {
        out[key] = toValue(value);
      }
      console.log(out);
    }
  });

  return out as T;
};
function toValue(mix: string) {
  const str = decodeURIComponent(mix);
  if (str === 'false') return false;
  if (str === 'true') return true;
  return +str * 0 === 0 ? +str : str;
}

enter image description here

1 Answer 1

1

From my understanding, Typescript still contains some glitches which is sometimes pretty hard to understand.

For example which is pretty connected to your case:

// (1)
// doesn't work since Typescript can't infer (string | number) as element
type Foo = string[] | number[];
const foo: Foo = [];
foo.push(1); // you would see error here as we push a number element

// (2)
// Works as expected
type Baz = Array<string | number>;
const baz: Baz = [];
baz.push(1);

Back to your case, I would suggest you to convert your type as case (2). Here is your code after converted:

// simplify things by group things again
type BaseType = string | number | boolean;
type BaseObj = Record<string, BaseType | BaseType[]>;

const fromQueryString = <T extends BaseObj>(
  querystring: string,
) => {
  const out: BaseObj = {};

  const arr = querystring.split('&');

  arr.forEach((a) => {
    const [key, value] = a.split('=');
    console.log(key, toValue(value), out, key in out);
    if (!!key && !!value) {
      if (key in out) {
        const v = out[key];
        out[key] = Array.isArray(v)
          ? v.push(toValue(value))
          : [v, toValue(value)];
      } else {
        out[key] = toValue(value);
      }
      console.log(out);
    }
  });

  return out as T;
};

function toValue(mix: string) {
  const str = decodeURIComponent(mix);
  if (str === 'false') return false;
  if (str === 'true') return true;
  return +str * 0 === 0 ? +str : str;
}

Sign up to request clarification or add additional context in comments.

Comments

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.