如何合并命名空间在 TypeScript 中没有导出接口

How to merge namespace has no exported interface in TypeScript

我在 TypeScript 中使用队列库 Bull。它的定义是:

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

我想在我的库中合并命名空间 Bull 并在另一个应用程序中使用它。

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'

根据文档,命名空间是一个全局变量,同名的命名空间将合并它们的导出接口。那么,如何从 @types/bull 合并命名空间 Bull?谢谢!

嗯,事实是 @types\bull 并没有真正声明命名空间。

嗯,是的,只是把相关类型的列表归为一组,作为默认导出一起导出,所以,它真正导出的是namespace的contents ,而不是命名空间本身。这就是为什么您可以导入 Queue,并使用 Queue 而不是 Bull.Queue,如果 Queue 确实属于某个命名空间,您应该这样做。

此外,我不知道你使用的是什么版本的 TypeScript,但你应该不能在同一个文件中使用 export (...)export = (...)。此外,当您将 export 添加到文件时,它会变成模块的声明文件,因此,最后,您将拥有一个默认导出命名空间的模块,然后您可以导入 Queues 来自 myLib,而不是 Job,因为 Job 没有出现在文件中的任何地方,因此它没有被导出。

为了能够合并不同文件中的名称空间,您不能使用导入或导出,只能使用声明,因为两个模块永远不能为同一个名称空间贡献名称。通过使用export,你把你的文件变成了模块,一旦你这样做了,它们中的命名空间就不再属于全局范围,所以即使它们有相同的名字,它们也确实属于范围他们自己的模块,不要合并。

要完成您想要做的事情,您必须拥有:

公牛:

declare const Bull: {
    (queueName: string, opts?: any): Bull.Queue;
    // something like above
  };

declare namespace Bull {
    interface Queue {}
    interface Job {}

    // some other non-exported interfaces
}

我的图书馆:

declare namespace Bull {
  export interface Queues {}
}

declare interface myInterface {
  foo: Bull.Queue | Bull.Queues
}

现在您真正拥有了一个包含两个声明内容的命名空间:

test.ts:

const a: Bull.Queues = {};
const g: Bull.Queue = {};
const b: Bull.Job = {};

这种方式可行,但不幸的是,您没有这种方式。您应该将 myLib 定义为:

import * as Bull from './bull';

export interface Queues {};


export interface myInterface {
  foo: Bull.Queue | Queues;
}

然后你可以使用:

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;

或者,如果您愿意,

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;

但是,无论如何,您都需要从 bullmyLib 导入。