通过模块扩充向现有 TypeScript 接口添加属性无效

Adding properties to existing TypeScript interface via module augmentation has no effect

我有一个依赖于 @types/hapi 的 Node 应用程序。我想将 属性 添加到此模块中定义的 classes 之一。我尝试通过模块扩充定义我的新 属性:

// my-custom-hapi-typings.d.ts
import * as hapi from 'hapi';

declare module hapi {
    interface Server {
        myProperty: string;
    }
}

这不会导致任何编译器错误,但它也不会将 myProperty 属性 添加到 Server class。当我尝试像这样引用 属性 时,我的项目中的其他地方仍然出现错误:

// my-other-file.ts
import * as hapi from 'hapi';

const server = new hapi.Server({ ... });

// error: Property 'myProperty' does not exist on type 'Server'.
server.myProperty = 'hello'; 

为什么 TypeScript 编译器似乎忽略了我的 .d.ts 文件?我是否需要 "import" 文件或以某种方式让 TypeScript 编译器知道该文件存在?我的印象是,只要在源目录中放置一个 .d.ts 文件就足以让 TypeScript 接受这些增强。

这是你的问题:

declare module hapi {

这实际上是在定义一个namespace, using older syntax that pre-dates ES6 modules which used to be called "internal modules". Writing module hapi is the same as writing namespace hapi, which is the preferred syntax today. More on namespaces vs modules here.

declare an external module你只需要将模块名称放在引号中:

[...] use a construct similar to ambient namespaces, but we use the module keyword and the quoted name of the module which will be available to a later import.

换句话说,只需将 hapi 放在引号中:

declare module "hapi"

现在你有一个环境my-custom-hapi-typings.d.ts不需要直接导入)外部模块定义(声明import "hapi" 给你什么),你可以扩充其中声明的内容。

如果将鼠标悬停在 module hapimodule "hapi" in the Playground 上,您会在工具提示中看到不同之处:

是的,由于其背后的历史,它很微妙且令人困惑。