[英]How can I merge typescript interfaces over multiple files in the same namespace
I am trying to refactor an unwieldy config interface/object by separating its various sections into separate files under a namespace
I've cleverly named Config
.我试图重构一个笨拙的配置接口/对象,方法是将其各个部分分成我巧妙命名的
namespace
下的单独文件Config
。
The documentation talks about namespaces that span multiple files and declaration merging of interfaces , but I can't seem to get them to work together.该文档讨论了跨越多个文件的命名空间和接口的声明合并,但我似乎无法让它们一起工作。
src/config/index.ts src/config/index.ts
/// <reference path="./server.ts" />
import fs from 'fs';
import json5 from 'json5';
const _config = readConfig();
namespace Config {
export const config = _config;
export interface IConfig {
someGeneralProperty: {
// ...
}
}
}
function readConfig(): Config.IConfig {
return json5.parse(fs.readFileSync('./path/to/config.json', 'utf-8'));
}
function doSomeOtherStuff() {
// fails: Property 'server' does not exist on type 'IConfig'.
console.log(_config.server.host);
}
src/config/server.ts src/config/server.ts
/// <reference path="./index.ts" />
namespace Config {
export interface IConfig {
server: {
host: string;
port: number;
}
}
}
src/index.ts源代码/索引.ts
// fails: Module '"./config"' has no exported member 'config'.
import { config } from './config';
// fails: Cannot use namespace 'Config' as a value.
// fails: Namespace 'Config' has no exported member 'config'.
import config = Config.config;
I've tried several variations of exporting things, such as export default Config;
我尝试了多种导出方式,例如
export default Config;
, export namespace Config {...}
in each of the src/config/...
files, changing export const config
to export var config
. ,
export namespace Config {...}
在每个src/config/...
文件中,将export const config
更改为export var config
。 In src/config/index.ts
I tried export * from './server'
.在
src/config/index.ts
我尝试export * from './server'
。 Nothing seems to help.似乎没有任何帮助。
I have a feeling I'm just going about this all wrong.我有一种感觉,我只是把这一切都错了。
Oddly, the interfaces within the namespace in every file are exported from the namespace, so in src/index.ts
, I can do:奇怪的是,每个文件中命名空间内的接口都是从命名空间导出的,所以在
src/index.ts
,我可以这样做:
import IConfig = Config.IConfig;
let c: IConfig;
console.log(c.server.host);
but I cannot do that in either src/config/index.ts
nor src/config/server.ts
.但我不能在
src/config/index.ts
或src/config/server.ts
做到这一点。
At first you should decide yourself, if you want to assign the config
object to a module scope (ie import
/ export
) or in the global scope (ie window
in browsers, global
in node).首先,你应该自己决定,如果你想指定
config
对象模块范围(即import
/ export
),或在全球范围内(即window
在浏览器中, global
的节点)。
The main purpose of namespaces is to define properties/values on the global scope.命名空间的主要目的是在全局范围内定义属性/值。 As you pointed out correctly with the links, equally named namespaces are merged - that includes contained inner members like the
IConfig
interface.正如您在链接中正确指出的那样,合并了同名命名空间 - 包括包含的内部成员,如
IConfig
接口。
Here is the deal: Merging only happens when the file containing the namespace
is a script (a non-module file without import
/ export
at top-level).这是交易:合并仅在包含
namespace
的文件是脚本(在顶级没有import
/ export
的非模块文件)时发生。
In src/config/index.ts
, you've got import
statements, so the file becomes a module and namespace Config
does not get merged.在
src/config/index.ts
,您有import
语句,因此该文件成为一个模块并且namespace Config
不会合并。 Instead it is rather a module internal namespace, which is not even export
ed (see Needless Namespacing , Do not use namespaces in modules in the docs).相反,它是一个模块内部命名空间,它甚至不是
export
ed(参见Needless Namespacing , Do not use namespaces in modules in the docs)。 The Config
namespace in src/config/server.ts
forms its own global namespace (non-module file), that is why you can still use the contained IConfig
type. src/config/server.ts
的Config
命名空间形成了它自己的全局命名空间(非模块文件),这就是您仍然可以使用包含的IConfig
类型的原因。
In summary, if you want to have the config (value and type) globally, make sure, every part of the multi file part namespace is declare in a non-module file.总之,如果您希望全局配置(值和类型),请确保多文件部分命名空间的每个部分都在非模块文件中声明。 If the config is to be exported from a module (preferred way if feasible!; better encapsulation, no global scope pollution, the "modern" way), read on.
如果要从模块导出配置(如果可行,首选方式!;更好的封装,没有全局范围污染,“现代”方式),请继续阅读。
src/config/server.ts: src/config/server.ts:
export interface ServerConfig {
server: {
host: string;
port: number;
}
}
// you could also read a server-specific config value here, export it
// and merge it with a separately read common config value in index.ts
// export serverConfig: ServerConfig = readServerConfig()
src/config/index.ts: src/config/index.ts:
import { ServerConfig } from "./server"
interface CommonConfig {
someGeneralProperty: {
// ...
}
}
export type IConfig = CommonConfig & ServerConfig
export const config: IConfig = readConfig(); // whatever readConfig looks like
src/index.ts:源代码/索引.ts:
import { config } from './config';
config.server;
config.someGeneralProperty
Feel free to adjust the parts, you need.随意调整零件,你需要。 Hope, it helps.
希望能帮助到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.