通过使用索引类型的方案获取值

时间:2019-05-07 20:43:50

标签: typescript generics

我有一个可以获取配置对象的类。我希望能够通过类公开的方法获取并设置值。

type ConfigValue = {name: string, value: string};
type Schema = {
    [key: string]: {
        someValue: boolean,
        values: ConfigValue[]
    }
}

class Config {
    constructor(private config: Schema) { }

    public getValue(key: string): ConfigValue {
        // ...
    }

    public setValue(c: ConfigValue): void {
        // ...
    }
}
Now I create an instance of Config and pass the configuration:
const conf: Schema = {
    'general': {
        someValue: true,
        values: [
            { 'name': 'title', 'value': 'Title' },
            { 'name': 'charset', 'value': 'utf-8' }
        ]
    },
    'http': {
        someValue: boolean,
        values: [
            { 'name': 'proxy', 'value': 'http://proxy' }
        ]
    }
}

const c = new Config(conf);
c.getValue('proxy');
c.setValue('title', 'New Title');

实现这一点应该可以,但是当实现这两种方法时,我遇到了一个问题:我可以遍历Schema中的每个对象,然后遍历values数组。但是,如果我能以某种方式获得钥匙,那会容易得多。我想到了泛型,将Scheme直接传递给类,这两种方法都可以使用它,但是现在我被方法类型定义所困。我首先想到了这一点:

class Config<T extends Schema> {
    constructor(private config: T) { }

    public getValue<K extends keyof T>(key: K): T[K]['values'] {
        return this.config[key].values;
    }
    …
}

K现在是字符串类型|数字(因为索引类型),而我的返回类型是T [K] [‘values’],即ConfigValues数组。但我的目标是,该键实际上是ConfigValue.name属性。我的返回类型也应该是ConfigValue类型。

public getValue<K extends keyof T>(key: string): T[K]['values'][??] {
    return this.config[??].values[key];
}

我不知道这是否是故意的,我也不应该直接在定义中键入键(T [K]-> ['groups'] <-)。希望这不会引起混淆,任何帮助或想法都会得到赞赏!

1 个答案:

答案 0 :(得分:0)

我认为TypeScript类型和JavaScript对象一团糟。请记住,TypeScript已转换为纯JavaScript。因此在程序执行期间将不存在任何类型。 TypeScript仅在编译期间起作用,而在执行期间消失。因此,无法使用TypeScrpt类型或泛型来提取某些数据或编写任何条件。类型仅用于检查是否将正确类型的参数传递给某个函数。

由于数组本质上是动态的(您可以在运行时添加/删除元素),因此无法键入检查数组内容。您不能依靠TypeScript来根据类型查找数组元素。

如果您希望ConfigValue.name是密钥,则应首先重构Schema。现在Schema包含ConfigValue的数组。除了迭代数组外,您无法提取数组的单个元素。如果可能,将配置存储为对象而不是数组。

仅当name属性在值数组中唯一时,才能转换为对象。

例如

type Schema = {
    [key: string]: {
        someValue: boolean,
        values: { [name: string]: ConfigValue }
    }
}

现在getValue看起来像

public getValue(key: string): ConfigValue {
    let configItem = Object.keys(this.config).find(k => this.config[k].values[key] !== undefined);
    return configItem.values[key];
}

根据您要传递config作为密钥的要求,仍然需要遍历ConfigValue.name个密钥。