问题
I am using the queue lib Bull in TypeScript. Its definition is:
node_modules/@types/bull/index.d.ts
declare const Bull: {
(queueName: string, opts?: Bull.QueueOptions): Bull.Queue;
// something like above
};
declare namespace Bull: {
interface Queue {}
interface Job {}
// some other non-exported interfaces
}
export = Bull
I want to merge the namespace Bull
in my library and use it in another app.
node_modules/myLib/index.d.ts
import { Queue } from 'bull'
declare namespace Bull: {
export interface Queues {}
}
export interface myInterface {
foo: Queue | Bull.Queues
}
export = Bull
myApp/foo.ts
import { Job, Queues } from 'myLib' // Error, 'myLib' has no exported member 'Job'
According to the doc, namespace is a GLOBAL variable, and namespaces of the same name will merge their EXPORTED interfaces. So, how can I merge the namespace Bull
from @types/bull
? Thanks!
回答1:
Well, the truth is that @types\bull
is not really declaring a namespace.
Well, it is, but just to group a list of related types and export them together as the default export, so, what it really exports are the contents of the namespace, not the namespace itself. That's why you can import Queue
, and use Queue
and not Bull.Queue
, which is what you should have to do if Queue
truly belonged to a namespace.
Besides, I don't know what version of TypeScript you're using, but you shouldn't be able to use export (...)
and export = (...)
in the same file. Besides, when you add export
to a file, it turns into a declaration file for a module, so, in the end, you have a module that exports a namespace as default, and then you can import Queues
from myLib
, but not Job
, as Job
does not appear anywhere in the file and therefore it is not exported.
To be able to merge namespaces in different files, you can't use imports or exports, just declarations, because two modules can never contribute names to the same namespace. By using export
, you're turning your files into modules, and once you do so, namespaces in them do not belong to the global scope anymore, so even if they have the same names, they really belong to the scope of their own module and do not merge.
To do what you're trying to do, you'd have to have:
bull:
declare const Bull: {
(queueName: string, opts?: any): Bull.Queue;
// something like above
};
declare namespace Bull {
interface Queue {}
interface Job {}
// some other non-exported interfaces
}
myLib:
declare namespace Bull {
export interface Queues {}
}
declare interface myInterface {
foo: Bull.Queue | Bull.Queues
}
And now you truly have one namespace with the contents of both declarations:
test.ts:
const a: Bull.Queues = {};
const g: Bull.Queue = {};
const b: Bull.Job = {};
This way it would work, but, unfortunately, is not what you have. You should define myLib
as:
import * as Bull from './bull';
export interface Queues {};
export interface myInterface {
foo: Bull.Queue | Queues;
}
and then you can use:
import * as Bull from './bull';
import { Queues, myInterface } from './myLib';
const a: Queues = {};
const g: Bull.Queue = {};
const b: Bull.Job = {};
const instance: myInterface = null;
or, if you prefer,
import * as Bull from './bull';
import * as ExtendedBull from './myLib';
const a: ExtendedBull.Queues = {};
const g: Bull.Queue = {};
const b: Bull.Job = {};
const instance: ExtendedBull.myInterface;
But, in any case, you need to import from both bull
and myLib
.
来源:https://stackoverflow.com/questions/49724861/how-to-merge-namespace-has-no-exported-interface-in-typescript