Typescript 接口对象 属性 值作为键

Typescript Interface objects property value as key

当尝试将对象数组映射到具有相同对象但使用 属性 值作为索引键的数组时,我尝试为情况创建正确的类型..

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;
}

谢谢。

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

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

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