1

I have a function that is a part of my utils package that I import in my other modules:

export function urlQueryParamParser(params: URLSearchParams) {
  const output:any = {};
  const searchParams = new URLSearchParams(params);

  new Set([...searchParams.keys()])
    .forEach(key => {
      output[key] = searchParams.getAll(key).length > 1 ?
        searchParams.getAll(key) :
        searchParams.get(key)
    });

  return output;
}

I export it like this in my index file along with other modules:

export * from './utils/urlQueryParamParser'

When I import it to my module:

import { urlQueryParamParser } from '@mypackages/utils'

and use it urlQueryParamParser(params) I get:

{
    "[object Iterator]": null
}

Where, if I just copy the function and use it as a part of the file where I am actually calling it, I get the right return result, something like this:

{
    "filter": "all",
    "query": "",
    "range": "today",
    "from": "2022-11-22",
    "to": "2022-12-22",
    "claims": [
        "damaged",
        "missing-article"
    ]
}

Why is the result different when I import this function as part of the other package from when I use it as a function in the file where I am calling it? The module where I am importing the function has following typescript version:

"typescript": "^4.7.2",

And the tsconfig.json of that module looks like this:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "target": "ESNext",
    "allowJs": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "module": "ESNext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "importHelpers": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "files": ["custom.d.ts"]
}

The typescript version of the package module is:

"typescript": "^4.7.4"

And the tsconfig.json looks like this:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist/", // path to output directory
    "baseUrl": "./src",
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "ESNext",
    "allowJs": false,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "importHelpers": true,
    "jsx": "react",
    "noEmit": false,
    "composite": true,
    "incremental": true,
    "declarationMap": true,
    "plugins": [{ "name": "typescript-plugin-css-modules" }]
  },
  "exclude": ["**/node_modules", "**/.*/", "dist", "build"],
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}
Ludwig
  • 1,401
  • 13
  • 62
  • 125
  • Since, it doesn't look like a named export, importing it as a named import won't work. Try something like, ```import * as parser from '@packages/utils' parser.urlQueryParamParser(params)``` – vicki Dec 07 '22 at 11:41
  • This may be a good read: https://2ality.com/2014/09/es6-modules-final.html – vicki Dec 07 '22 at 11:42
  • this is a named export @vicki – Ludwig Dec 07 '22 at 12:41
  • Your code seems to be typescript. Do you import a transpiled javascript version? There were some issues with `URLSearchParams` in older node versions https://stackoverflow.com/questions/63247242/how-to-use-urlsearchparams-in-a-node-js-and-typescript-project – kikon Dec 07 '22 at 12:53
  • I tried to reproduce your error with TypeScript 4.9.3 and couldn't. Can you provide your package.json and tsconfig.json? – Luigi Minardi Dec 07 '22 at 18:24
  • @LuigiMinardi I have added Typescript version and tsconfig of both packages module and the module where I am importing the function. – Ludwig Dec 07 '22 at 22:27
  • I am guessing, that you forgot the _spread_ in the module. So instead of `new Set([...searchParams.keys()])` you wrote `new Set([searchParams.keys()])`. That seems to be the only reasonable explanation. – Friedrich Dec 08 '22 at 10:45
  • Tested it and got this result when compiling it: https://codesandbox.io/s/busy-butterfly-uoj2bu?file=/src/index.ts – Friedrich Dec 08 '22 at 10:48
  • @Friedrich how can I configure typescript to use the spread in the module? – Ludwig Dec 08 '22 at 11:51
  • Usually, I just type it in there. Have you done so? Not using a set can also help - this will do some unnecessary work but that isn't too bad since URLs have max of 2000 chars anyways. – Friedrich Dec 09 '22 at 15:59

5 Answers5

4

Following up on my comment above.

I am guessing that the reason for this is that you forgot to spread the keys in your array in the file located in the package. Instead, you add the iterator object as the sole child into the array.

I think that you wrote new Set([searchParams.keys()]) instead of new Set([...searchParams.keys()]) in your current or previous version, and this incorrect piece of code got compiled wrongly (maybe it is even cached wrongly somewhere).

That said, I have no idea why TypeScript did not explicitly warn you when you did so. When reproducing the issue, I had to include // @ts-nocheck in my file.


Unfortunately, the issue is quite hard to reproduce since the information you gave was too sparse to create a working project. In the future, I recommend creating a CodeSandbox that contains the issue.

Friedrich
  • 2,211
  • 20
  • 42
0

If you're using TypeScript older than the 2.3.1 your TypeScript will not detect the URLSearchParams as an iterable object and then when you try to spread it it should not work then by javascript magic its making it return the [object Iterator] instead of raise an error.

Also your params should be a string (or URL['search'] if you want a better explanation of what is the params when reading your function) since passing the params as a string or the result of an other URLSearchParams return the same thing as the output.

As of why it works on some cases and other don't the only thing that I can think of is that the target version of your tsconfig.json and the typescript of your package.json does not match.

Or this @mypackages is using a different typescript version then the project that is using the function. If you can provide more information about the versions and environment that you're running the function it should be easier to solve the problem.

Luigi Minardi
  • 343
  • 4
  • 13
  • 1
    The @mypackages is using "typescript": "^4.7.4" while the project module where I am importing this function is using "typescript": "^4.7.2", so the packages has a newer version, which means it should be able to detect URLSearchParams as an iterable object – Ludwig Dec 07 '22 at 22:21
0

Shot in the dark here but, does it work if you replace your spread operator with Array.from?

export function urlQueryParamParser(params: URLSearchParams) {
  const output:any = {};
  const searchParams = new URLSearchParams(params);

  new Set(Array.from(searchParams.keys()))
    .forEach(key => {
      output[key] = searchParams.getAll(key).length > 1 ?
        searchParams.getAll(key) :
        searchParams.get(key)
    });

  return output;
}
Jostein S
  • 456
  • 7
0

In your module's tsconfig.json you have set noEmit to false, surely this should be set to true if you want it to actually compile.

Richard Dunn
  • 6,165
  • 1
  • 25
  • 36
0

Try to import it using its relative path.

import { urlQueryParamParser } from '../mypackages/utils'; // instead of '@packages/utils'

Or update the utils/index.js to:

import { urlQueryParamParser } from "./urlQueryParamParser";

export default {
  urlQueryParamParser
};
Ken Labso
  • 885
  • 9
  • 13