Typescript接口将对象的属性值作为键

时间:2018-02-03 20:13:20

标签: typescript generics typescript-typings

当我尝试使用相同的对象将对象数组映射到数组但使用属性值作为索引键时,我尝试为情境创建正确的输入法。

Code on playground

interface ValueDefinition {
    name: string;
}

function getByName<V extends ValueDefinition>(valuDefinitions: V[]) {
    let out  = {}

    for (const key in valuDefinitions) {
        out[valuDefinitions[key].name] = valuDefinitions[key];
    }
    return out;
}

const obj: ValueDefinition = {
    name: 'super'
};


const objKey = getByName([
    obj
]);

key.super; // Typings for this output

我正在寻找类似的东西:

type WithKey<D extends ValueDefinition> = {
    [key: D['name']]: D;
}

感谢。

1 个答案:

答案 0 :(得分:2)

您应该在ValueDefinition属性的字符串文字类型中使name接口通用,以便稍后提取它:

interface ValueDefinition<K extends string = string> {
    name: K
}

然后,您可以将getByName()函数的输出表示为以下映射类型:

type ValueDefinitionObject<K extends string> = {[P in K]: ValueDefinition<P>}

并修改getByName的签名在name文字集合中是通用的:

function getByName<K extends string>(valuDefinitions: Array<ValueDefinition<K>>): ValueDefinitionObject<K> {
    let out = {} as ValueDefinitionObject<K>
    for (const key in valuDefinitions) {
        out[valuDefinitions[key].name] = valuDefinitions[key];
    }
    return out;
}

此时它会起作用,但您必须小心声明obj,以便将值'super'的类型推断为'super'而不是string }。这个身份功能将有所帮助:

function asValueDefinition<K extends string>(vd: ValueDefinition<K>): ValueDefinition<K> {
    return vd;
}

好的,让我们尝试一下(我正在添加的另一个):

const obj = asValueDefinition({ name: 'super' });
const obj2 = asValueDefinition({ name: 'thing' });

如果您检查它们,则会显示为ValueDefinition<'super'>ValueDefinition<'thing'>

const objKey = getByName([obj, obj2]);  

objKey的输入为ValueDefinitionObject<'super'|'thing'>。让我们用它:

objKey.super; // okay, ValueDefinition<'super'>
objKey.thing; // okay, ValueDefinition<'thing'>
objKey.nope; // error, property 'nope' doesn't exist

这对你有用吗?祝你好运!