Hur använder jag en klass som är definierad i en TypeScript-deklarationsfil?


Jag försöker skapa en typings-fil för denna enkla köimplementation.

I mitt TS-projekt har jag skapat en mapp som heter customTypings och pekat på den i typeRoots-egenskapen i min tsconfig.json-fil.

Så här ser min .d.ts-fil ut:

declare module 'queue-fifo' {
    export default class Queue {
        constructor();
        isEmpty(): boolean;
        size(): number;
        clear(): void;
        enqueue(data: any): void;
        dequeue(): any;
        peek(): any;
    }
}

Jag importerar den som: import Queue från 'queue-fifo';

Och sedan försöker jag skapa en instans av Queue-klassen: const queue=new Queue();

Vid det här laget får jag inga typfel i VS Code, och jag får heller inga kompilationsfel. Däremot, när jag försöker köra min kod genom debuggern, får jag:

Exception has occurred: TypeError
TypeError: queue_fifo_1.default is not a constructor
    at BinarySearchTree.bfs (/../binarySearchTree.ts:110:23)
    at testBst (/../binarySearchTree.ts:139:10)
    at Object.<anonymous> (/../binarySearchTree.ts:144:1)
    at Module._compile (module.js:632:14)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)

Om jag bryter vid den raden ser jag att Queue (det jag importerade) är odefinierad, men queue_fifo_1 är definierad, och jag kan skapa en instans av klassen med det namnet medan jag är i debugkonsolen.

Kan någon förklara vad jag gör fel i min deklaration/konsumtion av deklarationen som orsakar detta oönskade beteende?

Svar #1

Lösning

Modulen queue-fifo använder CommonJS-stil export=Queue, vilket inte är kompatibelt med ES6-importer, och ger dig ingen standardexport. Den korrekta typdefinitionen måste använda samma export =-stil syntax:

declare module "queue-fifo" {
    class Queue {
        isEmpty(): boolean;
        size(): number;
        // etc
    }
    export = Queue;
}

Vilket kan importeras med CommonJS-stil import:

import Queue = require("queue-fifo");
const queue = new Queue();

ES6 import

Om du undrar om det är möjligt att importera den här modulen med ES6-syntax, kan du förmodligen använda namespace-definitionsknepet:

class Queue { /* ... */ }
namespace Queue { /* empty */ }
export = Queue;

Importera det sedan med ES6 jokertecken:

import * as Queue from "queue-fifo";
const queue = new Queue();

Men detta kommer endast att fungera i icke-ES6-miljöer, till exempel gör bundlers som Webpack och Rollup detta möjligt idag, men framtida ES6-kompatibla modulsystem kommer inte att kunna göra detta. Se mer här: Vad betyder "... resolves to a non-module entity and cannot be imported using this construct"?

Relaterade artiklar