我正在尝试为特定于我们应用的config
模块添加类型。 config
模块是从JSON文件动态生成的,因此键入起来很麻烦。由于它是节点模块,因此我使用ambient module进行输入。
// config.d.ts
declare module 'config' {
interface AppConfig {
name: string;
app_specific_thing: string;
}
const config: AppConfig;
export = config;
}
我还如何导出AppConfig
,以便可以将其用作如下类型:
import * as config from 'config';
const appConfig: config.AppConfig;
如果我直接在config
模块中导出AppConfig,则会出现以下错误:
TS2309:导出分配不能在具有其他导出元素的模块中使用。
如果我将AppConfig
移至另一个文件(例如./app_config
)以保存导出并将其导入config.d.ts
,则会出现以下错误:
TS2439:环境模块声明中的导入或导出声明不能通过相对模块名称引用模块。
如果我将AppConfig
导出文件放在同一文件中,但在config
模块之外,则会出现以下错误:
TS2665:扩充中的模块名称无效。模块'config'解析为$ PROJ / config / lib / config.js上无法键入的模块,无法对其进行扩充。
这类似于Typescript error "An export assignment cannot be used in a module with other exported elements." while extending typescript definitions,但要求我希望能够直接将AppConfig
作为类型导入其他TS文件中。
答案 0 :(得分:0)
答案需要一个令人困惑的打字稿概念:
Declaration merging-编译器将两个用相同名称声明的独立声明合并为一个定义。在这种情况下,我们创建两个config
的声明。
// config.d.ts
declare module 'config' {
// This nested namespace 'config' will merge with the enclosing
// declared namespace 'config'.
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html
namespace config {
interface AppConfig {
name: string;
app_specific_thing: string;
my_enum: FakeEnum;
}
interface MyInterface {}
// See side note below
type FakeEnum = 'A' | 'B' | 'C';
}
const config: AppConfig;
export = config;
}
您可以像这样使用导入:
import * as config from 'config';
import { FakeEnum, MyInterface } from 'config';
请注意,您不能将enums
与ambient module(declare module 'config'
)一起使用,因为枚举会编译为JS对象,并且无法将新对象添加到模块中不要管您可以通过伪装具有联合类型的枚举来解决此问题:
type FakeEnum = 'A' | 'B' | 'C';