tfoxy / chrome-promise

Promises for chrome JavaScript APIs used in extensions and apps.
MIT License
150 stars 14 forks source link

Can't import from Typescript #19

Closed zmbq closed 6 years ago

zmbq commented 6 years ago

I'm trying to use chrome-promise in a Typescript Chrome Extension. The documented ES usage is:

import ChromePromise from 'chrome-promise';

const chromep = new ChromePromise();
chromep.something_or_other('param');

When I do the same in Typescript everything transpiles properly - ChromePromise is recognized with the right type information. Intellisense is shown, Typescript catches errors if I call a non-existing method - it's all fine.

At runtime, however, I can't create the ChromePromise instance. I get the following error:

Uncaught TypeError: chrome_promise_1.default is not a constructor
    at Object.__WEBPACK_AMD_DEFINE_ARRAY__ (background.js:77)
    at __webpack_require__ (background.js:20)
    at Object.defineProperty.value (background.js:63)
    at background.js:66

And indeed, chrome_promise_1.default is undefined, while chrome_promise_1 is a function.

Changing the import to import { ChromePromise } from ... results in an error saying ChromePromise is undefined.

import * as ChromePromise from ... yields an error saying ChromePromise has no type.

There's also a Stack Overflow question: https://stackoverflow.com/questions/47651244/cant-import-from-chrome-promise-in-typescript

NaridaL commented 6 years ago

I saw your SO question. As far as I can see, the typings are wrong. They declare a default export but that isn't reflected in the JS. The typings should have the form:

class ChromePromise {
}
export = ChromePromise // so require() works
export as namespace ChromePromise // so global is accessible

You would then use it as Import CP = require('chrome-promise'), or with syntheticDefaultExports: import CP from 'chrome-promise'.

tfoxy commented 6 years ago

Hi! I think I used webpack when I tested typescript. Let me check tomorrow if I find anything. I will try @NaridaL solution first.

tfoxy commented 6 years ago

From what I tested, the problem is in the generated code. So the typings should not matter. I think it is related to #15 . Disabling amd in webpack should work. But it's better if I fix it in the code. I will try to release a new version this weekend.

zmbq commented 6 years ago

I disabled AMD by adding the following to my module loaders:

{ test: /\.js$/, loader: 'imports-loader?define=>false' }

It did not make any difference. So either this isn't the solution, or that's not the right way to disable AMD on Webpack.

tfoxy commented 6 years ago

To disable AMD in Webpack:

module: {
  rules: [
    { parser: { amd: false } }
  ]
}

Source: https://github.com/webpack/webpack/issues/3017#issuecomment-285954512

rafis commented 6 years ago

This is critical bug, please fix. I do not understand how to disable AMD, at least just adding these lines into webpack config doesn't work.

tfoxy commented 6 years ago

I released a new version (v2.1.2). If it doesn't work, let me know. Thanks to @rafis for the PR.

Quantumplation commented 6 years ago

@tfoxy I'm on v3.0.0 and seem to be encountering this error.

If I try what's listed in the documentation:

import chromep from 'chrome-promise';
chromep.tabs; // <-- type error, because typescript things chromep is the ChromePromise constructor

but

import ChromePromise from 'chrome-promise';
const chromep = new ChromePromise();
chromep.tabs...; // This compiles, but the transpiled code fails

I was able to get it working through the following snippet:

import * as ChromePromise from 'chrome-promise';
// At this point, typescript things that "ChromePromise" is an object containing a single property, called "default", which points to a class, but in actuality it is an instance of that class.  So, using anys...
const chromep = ChromePromise as any as ChromePromise.default;

chromep.tabs...; // Now works AND typechecks
tfoxy commented 6 years ago

I forgot to update the typings when changing the api in v3 (facepalm). I will release v3.0.1 when I have the time.

Quantumplation commented 6 years ago

No worries. Would you accept a pull request that fixed them? :)

tfoxy commented 6 years ago

Of course! You can update the typings file directly. It is generated from another script, but that code is really ugly and it's only there to update the typings in case an api is added. So I doubt the script will be used again soon.

tfoxy commented 6 years ago

v3.0.1 fixes the typings in v3

Quantumplation commented 6 years ago

The typings don't appear to be fixed for me.

import chromep from 'chrome-promise';

...

const tab = await chromep.tabs.get(tabId);

At runtime, this gets transpiled to:

chrome_promise_1.default.tabs.get(...);

but default is undefined, so I get:

Uncaught (in promise) TypeError: Cannot read property 'tabs' of undefined
    at Popup.tsx:66
    at step (Popup.tsx:41)
    at Object.next (Popup.tsx:22)
    at Popup.tsx:16
    at new Promise (<anonymous>)
    at __awaiter (Popup.tsx:12)
    at getMas (Popup.tsx:59)
    at Popup.<anonymous> (Popup.tsx:91)
    at step (Popup.tsx:41)
    at Object.next (Popup.tsx:22)
tfoxy commented 6 years ago

Check v3.0.2 . It has to do with the way typescript handles CommonJS modules.

Quantumplation commented 6 years ago

Thanks, v3.0.2 worked for me!