2

I am using Typescript with Nodejs, Windows 7 Ultimate x64. Compiler is tsc.

I am modifying an existing codebase which has many files sharing a namespace. So, at the top of each file there is a declaration like so:

namespace program {
    ...
}

I am trying to get the library JSZip working in this existing codebase, but I was running into some weirdness that I think has to do with this namespace.

Before I get started, I want to describe how I set up the library. First I invoked npm like so to install:

npm install --save jszip
npm install --save @types/jszip

Then I set up my tsconfig.json to include this:

var map = {
    'jszip':                      'node_modules/jszip/dist/jszip.min.js'
};

I'm not sure that step matters but it might allow calling the import "jszip" down below.

Then I tried a few import commands in the code, but was hit with errors. First I tried:

import * as JSZip from 'jszip';

namespace program {
    ...
}

But this causes a large count of errors within that file. I get "namespace is declared but never used" warnings for that large namespace, at least within the file I am performing the import call in. Every reference to an external file within that namespace is also broken, and for those I get a "Cannot find name '...'" error. So calling the import like that seems to be incompatible with the use of a namespace.

So then I tried:

namespace program {
    import * as JSZip from 'jszip';

    ...
}

So, in this case I at least do not get file-wide errors, but that line is still creating errors. The two I get are "Import declarations in a namespace cannot reference a module." and "Cannot find module 'jszip'" (notably, I do not get the latter error when using the previous method.)

So this makes me think something is wrong in my approach or setup, but even though I am stuck at a relatively simple point I have not been able to find a resource yet to help understand the exact issue. Of course I found some resources that I've cobbled together a limited understanding with at least though, links here:

types/jszip: https://www.npmjs.com/package/@types/jszip

jszip: https://www.npmjs.com/package/jszip

This is a close example but not identical to my case. I don't think the solutions proposed will work in my situation, but I could be wrong: How to use namespaces with import in TypeScript

This is where I got the clue for the "import * ..." syntax and adding the "map" property to tsconfig: Import JSZip in Angular 2 project

3
  • What do you mean by var map = in your tsconfig.json? Usually that file can contain only JSON not JavaScript. The example of using map that you linked to is doing that in a systemjs.config.js file not in a tsconfig.json file. I suggest removing that; it might just fix the error. Commented May 14, 2019 at 4:22
  • Right, it seems I was misreading one of my references. I have modified it now to more or less match the example below. It is not resolving my error at its root though. It's strange I didn't get an error message for having completely off the wall code in tsconfig though. Is that an intentional feature? Commented May 15, 2019 at 0:44
  • I don't think it's an intentional feature to allow completely off the wall code in tsconfig. That said, I am not on the TypeScript team. Commented May 15, 2019 at 2:57

1 Answer 1

1

How to use JSZip in an old-fashion ambient project with concatenated JavaScript files

From the official documentation, JSZip can be installed manually:

Manually : download JSZip and include the file dist/jszip.js or dist/jszip.min.js

For TypeScript, the easiest way is without typings. Create a new file with this content:

// global-defs.d.ts
declare const JSZip: any;

Or, you can try to import typings manually. Create a file jszip.d.ts and paste all the content of its typings. Now, remove the last line export = JSZip;. Your file ends with:

declare var JSZip: JSZip;

Then, the code from the package documentation should works.

The classic solution for a brand new project

In a clean directory:

npm init
npm install --save jszip
npm install -D @types/jszip typescript

Then, create a valid tsconfig.json file. For example:

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
  },
  "exclude": [
    "node_modules"
  ]
}

Create a source file:

// main.ts
import JSZip = require('jszip');

// Here, use the code from the package documentation
// here: https://www.npmjs.com/package/jszip

Some advice:

  • Do not use import * as JSZip for something that is not a module namespace object. You should use import JSZip = require(…) in your case.
  • Do not use TypeScript namespaces and ES6 modules together. Your code imports a module, so just remove your namespace program.

More documentation on ES6 modules (including module namespace objects) here.

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

8 Comments

Thanks for the advice. That does indeed work in a vacuum, but I am modifying an existing and decently large codebase with "namespace program {" at the start of each file and several other namespaces declared besides. I do not think removing use of namespaces is the appropriate solution in my case. Is there a way to not completely break the architecture of this existing codebase and still use JSZip? At any rate I am starting to do just that, but I may be cowed by the large workload it implies. It strikes me as a bit absurd to require this amount of disruption for use of one library.
Just an update - removed all uses of "namespace" from my code. I saw many errors with inter-module references and started using "import {...} from "./x.ts"" syntax where needed. I also had to modify my compiler options as my usage of a Web Audio reference mysteriously broke, too. In the end the "require" forced me to use the "--module amd" compiler tag which meant I had to move over to requirejs. And in the end the ts would compile without error but the project would fail to initialize. No errors on web console. I may have to revert at this point (I have it under revision control thankfully).
@EmptySet The existing code base does not use import or export at all?
Some classes/functions are "export" but there are no explicit "import"s (instead triple-slash references to files in the same namespace are used). Removing the namespaces without changing anything else caused errors in this architecture though I can't remember exactly what at the moment. It may have been "Cannot use output in module without --module set to "system" or "amd"", the direct fix for which I wanted to eschew for a while. This led me down the road of changing architecture. I will share the exact errors when I have a chance to revert and look at it again.
Okay, looks like that simple route worked without modification of the codebase (the upper suggestion in your reply). I am surprised it was that straightforward. Thanks!
|

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.