How can I get TypeScript to load the PDF.js NPM module and @types bindings in a way that generates working Node.JS code?
Asked Answered
C

7

16

Context

I'm trying to import PDF.JS into a TypeScript project. I'm using the DefinitelyTyped bindings for pdfjs-dist, installed via npm install @types/pdfjs-dist and npm install pdfjs-dist.

Problem

I can't seem to get TypeScript to compile my project. I'm using source code copied straight from the tests on DefinitelyTyped. This is the simplified (deletions only) code I'm trying to compile (an exact copy of the test code from DefinitelyTyped also fails in the same way):

import { PDFJSStatic } from 'pdfjs-dist';
var PDFJS: PDFJSStatic;
PDFJS.getDocument('helloworld.pdf').then(console.log);

TypeScript finds the type declarations module, and considers the import of PDFJSStatic to be valid. It doesn't think PDFJS is ever initialized, but if I turn off strict in tsconfig, the code compiles, but it compiles to:

"use strict";
exports.__esModule = true;
var PDFJS;
PDFJS.getDocument('helloworld.pdf').then(console.log);

Which obviously doesn't work. It's not compiling the import statement into anything.

Question

How can I import PDF.JS into a TypeScript project and compile it into working Node.JS code via the declaration files in @types/pdfjs-dist?

What I've Tried

I've tried different variations on import, to no avail. Switching to require also doesn't seem to help.

I've verified that the pdjs-dist dependency, and the @types/pdfjs-dist dependencies are present, updated, and usable directly from NodeJS (non-TypeScript programs).

I've tried various values for module in my tsconfig. They change the generated code sometimes, but none of them change it to contain the needed import.

I've tried adding /// <reference path="../node_modules/@types/pdfjs-dist/index.d.ts" /> above the import line. That didn't change the behavior.

Environment

tsc version 2.4.2, node 8.5, and npm 5.3. I have the following tsconfig.json in my project root:

{
    "compilerOptions": {
        "allowJs":true,
        "rootDir": ".",
        "outDir": "dist",
        "moduleResolution": "node"
    },
     "include": [
        "src/**/*"
    ],
    "exclude": [
        "**/*.spec.ts",
        "dist/**/*"
    ]
}
Commodious answered 13/10, 2017 at 22:13 Comment(0)
T
10

Maybe you can use require function.

Add @types/node packages, and write require('pdfjs-dist') at the top of the your source code. So, you can modify your code like below.

Now, this code will work.

import { PDFJSStatic } from 'pdfjs-dist';
const PDFJS: PDFJSStatic = require('pdfjs-dist');
PDFJS.getDocument('helloworld.pdf').then(console.log);

I think that @types/pdfjs-dist has problems in its implementation.

Teriann answered 12/11, 2017 at 9:57 Comment(2)
Now, this method does not work. Please see this change of @types/node github.com/DefinitelyTyped/DefinitelyTyped/commit/…Teriann
Now, this code will work. import { PDFJSStatic } from 'pdfjs-dist'; const PDFJS: PDFJSStatic = require('pdfjs-dist'); PDFJS.getDocument('helloworld.pdf').then(console.log); I think that @types/pdfjs-dist has problems in its implementation.Teriann
L
6

With @types/pdfjs-dist 2.1.0 and pdfjs-dist "2.1.266", the fundamental issue still doesn't quite seem fixed, but I've found that the approach from their own test works:

import { getDocument, PDFDocumentProxy, PDFPromise, Util } from 'pdfjs-dist';

(It's not pretty, though, as it pollutes your namespace.)

Lilias answered 29/8, 2019 at 17:2 Comment(0)
D
1

I've also tried different ways. For me, the most readable was this one:

import * as pdfjslib from 'pdfjs-dist';
let PDFJS = pdfjslib.PDFJS;
PDFJS.disableTextLayer = true;
PDFJS.disableWorker = true;
Denial answered 11/12, 2017 at 22:4 Comment(1)
This does not work. I get cannot use namespace 'pdfjslib' as a value.Commodious
M
1

This worked for me, without having to use require:

import * as pdfjslib from "pdfjs-dist";
const PDFJS = (<any>pdfjslib) as PDFJSStatic;

You just have to silence the type errors by casting the module to any.

The typings in @types/pdfjs-dist are definitely incorrect, but this should be a quick workaround. :)

Mexico answered 18/7, 2018 at 4:22 Comment(0)
N
1

If you happen to be using React you can use react-pdf package which uses pdfjs under the hood. It also has it's own typings so you can import this without needing require.

Natala answered 2/5, 2021 at 4:33 Comment(0)
R
1

Gave it a rubberband solution. Was tired of getting errors spread across multiple components and moved the pdfjslib to a single one. Now my other components refer to this one without errors, and only that component shows errors on import.

export { PDFDocumentLoadingTask, PDFDocumentProxy, 
PDFPageProxy, getDocument } from 'pdfjs-dist';
import * as pdfjsLib from 'pdfjs-dist';
(pdfjsLib as any).GlobalWorkerOptions.workerSrc = 
`//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.8.162/pdf.worker.js`;
export { pdfjsLib };
Radius answered 9/8, 2023 at 11:32 Comment(1)
Awesome. Worked great! Few notes since this was posted: Use cdnjs.com/libraries/pdf.js to get the CDN libraries available to match with your installed NPM of pdfjs-dist. At the time of this comment 4.x is not supported for this solution since no CDN is available so I went back to the latest 3.x version.Invaginate
P
0

The following works.

  • pdfjs-dist v3.5.141
  • typescript v3.9.10
import * as pdfjsLib from 'pdfjs-dist/webpack'

...

    // in this example, data is a Uint8Array
    const pdf = await pdfjsLib.getDocument({ data }).promise
    for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
      const page = await pdf.getPage(pageNum)
      ...

Also it doesn't hurt to have a file, "pdfjs-dist.d.ts":

declare module 'pdfjs-dist/webpack'
Parrott answered 1/5, 2023 at 21:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.