TypeScript - 属性 在使用 toml 解析后对象上不存在
TypeScript - property does not exist on object after parsing with toml
我的 TypeScript 项目是模块化的,有几个配置文件。
我选择 TOML 作为配置文件,因为它是一种非常直观的语言。
另外,我有一个 main.toml
可以 enable/disable 模块的地方。
我的配置 class 看起来像这样。它用于从中创建自动解析的多个配置。
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
:
时,打字稿编译器都会给我以下错误
TS2339: Property 'modules' does not exist on type 'object'.
我可以用 @ts-ignore
来抑制它,顺便说一下,它工作得很好,但我认为这是一些不好的做法,我想知道我是否可以以某种方式阻止它。
我还尝试了其他 TOML 解析器,例如 this,我希望它能有所作为,但我遇到了完全相同的问题。
Typescript 无法推断已解析配置的结构。请记住,Typescript 存在于 compile-time,但不存在于运行时,并且您解析的配置对象存在于运行时但不存在于编译时。
你告诉 Typescript 你解析的配置是 object
类型,但是 object
没有 modules
属性.
这里有两个选择:
- 将
_config
定义为 any
而不是 object
。这将告诉 Typescript 该对象可以是 any 类型,这意味着它基本上不会被类型检查。
- 为你的配置对象定义接口,这样 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);
}
我的 TypeScript 项目是模块化的,有几个配置文件。 我选择 TOML 作为配置文件,因为它是一种非常直观的语言。
另外,我有一个 main.toml
可以 enable/disable 模块的地方。
我的配置 class 看起来像这样。它用于从中创建自动解析的多个配置。
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
:
TS2339: Property 'modules' does not exist on type 'object'.
我可以用 @ts-ignore
来抑制它,顺便说一下,它工作得很好,但我认为这是一些不好的做法,我想知道我是否可以以某种方式阻止它。
我还尝试了其他 TOML 解析器,例如 this,我希望它能有所作为,但我遇到了完全相同的问题。
Typescript 无法推断已解析配置的结构。请记住,Typescript 存在于 compile-time,但不存在于运行时,并且您解析的配置对象存在于运行时但不存在于编译时。
你告诉 Typescript 你解析的配置是 object
类型,但是 object
没有 modules
属性.
这里有两个选择:
- 将
_config
定义为any
而不是object
。这将告诉 Typescript 该对象可以是 any 类型,这意味着它基本上不会被类型检查。 - 为你的配置对象定义接口,这样 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);
}