使用toml分析后,对象上不存在TypeScript-属性



My TypeScript项目是模块化的,有几个配置文件。我选择TOML作为配置文件,因为它是一种非常直观的语言。

此外,我有一个main.toml,您可以在其中启用/禁用模块。我的配置类如下所示。它用于创建多个自动解析的配置。

import { parse } from 'toml';
import { readFileSync } from 'fs';
import { join } from 'path';
export class Config {
private readonly _name: string;
private readonly _path: string;
private _config: object;
constructor(name: string) {
this._name = name;
this._path = join(__dirname, '..', '..', 'config', `${name}.toml`);
this._config = this.load();
}
public load(): object {
let config: object = {};
try {
config = parse(readFileSync(this._path).toString());
} catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`config ${this._name}.toml was not found!`);
} else {
throw new Error(error);
}
}
return config;
}
get config(): object {
return this._config;
}
}

这就是我的主文件在我想使用main.toml激活其他模块的地方的样子:

import { Config } from './init/config';
let config: object = {};
try {
config = new Config('main').config;
} catch (error) {
console.log(error.stack);
process.exit(1);
}
for (const key in config.modules) {
if (Object.prototype.hasOwnProperty.call(config.modules, key) && config.modules[key]) {
require(`./modules/${key}/${key}`);
} else {
zoya.info(`skipping module ${key}...`);
}
}

现在我遇到的问题是,每次使用config.modules时,typescript编译器都会给我以下错误:

TS2339: Property 'modules' does not exist on type 'object'.

我可以用@ts-ignore来抑制它,顺便说一句,它效果很好,但我认为这是一种糟糕的做法,我想知道我是否能以某种方式防止这种情况发生。

我还尝试了其他TOML解析器,比如这个,我希望它能有所不同,但我遇到了完全相同的问题。

Typescript无法推断解析后的配置的结构。请记住,Typescript在编译时存在,但不在运行时存在,解析后的config对象在运行时也存在,但在编译时不存在。

您告诉Typescript,您解析的配置类型为object,但object没有modules属性。

这里有两个选项:

  1. _config定义为any而不是object。这将告诉Typescript,该对象可以是任何类型,这意味着它基本上不会被类型检查
  2. 为配置对象定义接口,这样Typescript就知道应该从中获得什么类型。琐碎:
interface ConfigDef {
modules: SomeType[]
}
let config: ConfigDef = { modules: [] };
try {
config = new Config('main').config as ConfigDef;
} catch (error) {
console.log(error.stack);
process.exit(1);
}

或者,更严格地说,使用泛型(这可能更好(:

export class Config<T> {
private readonly _name: string;
private readonly _path: string;
private _config: T;
constructor(name: string) {
this._name = name;
this._path = join(__dirname, '..', '..', 'config', `${name}.toml`);
this._config = this.load();
}
public load(): T {
let config: T = {};
try {
config = parse(readFileSync(this._path).toString()) as T;
} catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`config ${this._name}.toml was not found!`);
} else {
throw new Error(error);
}
}
return config;
}
get config(): T {
return this._config;
}
}
// ...
let config: ConfigDef = { modules: [] };
try {
config = new Config<ConfigDef>('main').config;
} catch (error) {
console.log(error.stack);
process.exit(1);
}

最新更新