metafloor / bwip-js

Barcode Writer in Pure JavaScript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Property 'toCanvas' does not exist on type 'typeof BwipJs'

Harry-Chalcraft opened this issue · comments

This issue is still not solved with 4.1.2

Currently using react 18.2.0

How do you expect me to help you when you have provided no details on your problem?

Please read: https://freecodecamp.org/news/how-to-ask-a-question-on-a-forum/

I do apologize, let me try again:
I am using BwipJs on a React Typescript project to display a bar code by using the toCanvas method, everything is working well on the v3.0.4.
However when i upgrade the package to 4.1.2 i get a type error on this method which says:
Property 'toCanvas' does not exist on type 'typeof BwipJs'
I saw there had been an issue already opened for this problem that was meant to be solved in the 4.1.2 but it hasn't.

Since it looks like typescript is grabbing the wrong import, please try the following:

import bwipjs from "bwip-js/browser";

This is a to be documented feature, once more real world testing has been acquired....

Thanks for that but in that case it cannot find the module "bwip-js/browser" is there another dependency to install ?

Are you using a modern version of the typescript compiler/bundler? It appears your version does not understand the exports map in package.json.

This is an issue for me, as well, also using TypeScript/React. I'm using the latest version of the TypeScript compiler, 5.3.2 as of right now. I was able to clear the error and get the hover text working by messing with bwip-js package.json but I don't know what I'm doing there enough to provide a clean fix.

TypeScript calls it an error but it works when run. Without using the suggested fix, with import statement:

import bwipjs from 'bwip-js'

the error is shown on toCanvas as:

Property 'toCanvas' does not exist on type 'typeof BwipJs'.ts(2339)

When using:

import bwipjs from 'bwip-js/browser'

the error is shown on the import:

Cannot find module 'bwip-js/browser' or its corresponding type declarations.ts(2307)

Still works in both cases.

Interesting that the code works. The actual issue is the compiler failing to find the types declaration. Looking more in depth at the typescript docs, this caught my eye:

When resolving through conditional "exports", TypeScript always matches the "types" and "default" conditions if present.

I think we can leverage that behavior. In the file bwip-js/package.json, please find:

      "./browser": {
          "types": "./dist/bwip-js.d.ts",
          "import": "./dist/bwip-js.mjs",
          "require": "./dist/bwip-js.js"
      },

And replace with:

      "./browser": {
          "import": {
              "types": "./dist/bwip-js.d.ts",
              "default": "./dist/bwip-js.mjs"
          }
      },

In your code, use the qualified import:

import bwipjs from 'bwip-js/browser';

Unfortunately, this didn't work for me, but I saw where you were going and tried messing with it for a while. I didn't find a clean solution, but what worked for me was to change:

"main": "./dist/bwip-js-node.js",

to:

"main": "./dist/bwip-js.js",

As a result, I realized I was instead able to import from a full path, i.e.

import bwipjs from '../../node_modules/bwip-js/dist/bwip-js';

and it was properly recognized and worked.

If I try to do:

import bwipjs from 'bwip-js/dist/bwip-js

I get an error:

Missing "./dist/bwip-js" specifier in "bwip-js" package

and it doesn't work. It did lead me to this: evanw/esbuild#1484 but their solution also didn't work.

It seems to be skipping the exports entirely. It may just be the way my project is configured. I realize that this isn't a fix for you, but maybe it's a clue.

That pretty much proves the compiler is not using the exports map for module resolution. Possibly you have an out-of-date config file that is preventing the compiler from using it? Other than that, there is not much more I can do. The obsolete main and browser entries in package.json should not be used by toolchains in 2023.

Hi, I've just installed version 4.2.0 of your package, for a react native project (expo v50 sdk). es imports are not importing the proper export for react native, and therefore toDataURL does not exist. I've attempted your previous suggestions as trying to import directly from import bwipjs from 'bwip-js/react-native'; and it fails for the same reason, (TS2307: Cannot find module  bwip-js/react-native  or its corresponding type declarations.). We are on ts version 5.3.3

@z1haze : Please post a zip of a minimal app that exhibits the behavior. Make sure it includes the configuration file(s) you are using. I will try to get this figured out.

we were able to get things "working" by adding our own path alias to the tsconfig for your package to resolve the correct type declarations: "bwip-js": ["node_modules/bwip-js/dist/bwip-js-rn.d.ts"],. This of course, is not ideal and would appreciate if you can track down and resolve it properly

This was an interesting rabbit hole to go down. Not sure what the expo package is (not a react-native developer), but its tsconfig.base.json is setting moduleResolution:node, which prevents using exports maps correctly. This is what I found is required in your local tsconfig.json:

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "module":"nodenext",
    "moduleResolution":"nodenext",
    "customConditions":["react-native"]
  }
}

To debug this, I used the --explainFiles option on tsc. It gave the following tidbit of information:

Type library referenced via 'node' from file 'node_modules/bwip-js/dist/bwip-js-node.d.ts' with packageId '@types/node/index.d.ts@20.11.16'

So it was using the exports map, but for the node condition, rather than the react-native condition. And forcing the react-native condition required all three of the added lines in tsconfig.json. Please give that a try and let me know if it works with a more general/complex application.

Alternatively, you can use the explicit import bwipjs from 'bwip-js/react-native' and omit the custom condition in tsconfig.json:

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "module":"node16",
    "moduleResolution":"node16"
  }
}

For both of these usages, you must be using at least node16 or nodenext for the module resolution.

Hey @metafloor, thanks for looking into this. Expo is just an SDK for react native. I guess you can consider it the nextjs for native apps. using react-native. That said, I applied your suggested fixes, and while it does make the compiler happy, and module resolution appears to function properly, the bundler still blows up because it cannot resolve the module (when referencing the import via import bwipjs from 'bwip-js/react-native';
image

Also, we use node 18, if that matters. Lastly, the bundler is metro, so if there's something that needs to happen with that too, please let us know. This though, if the first time I've ever had an issue with a package module resolution like this. When stuff like this happens I tend to lean more toward an issue with the package structure and not the other way around... e.g. if 19/20 are in a line, and one is out of line, who is wrong?

The difference between bwip-js and other packages is that there are three separate platform targets: browser, node, and react-native. And actually four since there is a generic svg-only target as well. Most (almost all) packages either support a single generic javascript target or a single platform. The exports map is relatively new - node v12 was released in 2020 - and not enabled by a lot of bundlers. For example, here is metro's exports map documentation. It is not enabled by default.

So for metro, you need to set unstable_enablePackageExports: true. See https://metrobundler.dev/docs/configuration/#unstable_enablepackageexports-experimental.

Please use the alternate tsconfig.json configuration posted above with import bwipjs from 'bwip-js/react-native'. I am thinking that is the long-term solution as relying on a react-native condition being auto-selected by the typescript compiler and bundler is not workable.

Alright, that works for me. Thank you for getting to the bottom of this!