如何在现有但当前未知的键/值对上设置接口?

时间:2019-05-08 15:17:36

标签: typescript interface

我有以下界面:

interface Item {
    _id: string;
    name: string;
    amount: number;
    type: 'a' | 'b' | 'c';
    value: string;
}

现在,我想创建一个通用方法来更新一个值,该值可以是五个中的任何一个

简化后,该函数看起来像:

patch(item: Item, key: any, value: any): Item {
    return {
        ...item,
        [key]: value
    };
}

  • key使用什么?
  • value使用什么?

2 个答案:

答案 0 :(得分:2)

由于值类型取决于,因此您应该使用通用类型参数。

  • 我们可以将Key定义为Item的扩展key(这意味着Key可以分配给Item的类型key)
  • 然后使用Key索引值的项目类型(Item [Key])。

结果:

function patch<Key extends keyof Item>(item: Item, key: Key, value: Item[Key]): Item {
    return {
        ...item,
        [key]: value
    };
}

您可以进一步进行抽象一步。知道此项目的类型并不重要:

function patch<TItem, TKey extends keyof TItem>(item: TItem, key: Key, value: TItem[Key]): TItem {
    return {
        ...item,
        [key]: value
    };
}

现在,无论您传递什么物品,都可以修补一个值

答案 1 :(得分:2)

您的原始代码将允许像{p>这样不幸地调用patch

declare const item: Item;
patch(item, 7, false); // no error 

尽管7不是Item的有效属性键,而false不是该属性或Item的任何键的有效属性值。 / p>


让我们检查一下您特定的Item界面,看看keyof and lookup types对它的作用。

keyof类型运算符采用对象类型并返回其键的类型。如果对象没有index signature,则该类型应为literal types的并集,对应于其已知有效键:

type KeysOfItem = keyof Item
// type KeysOfItem = "_id" | "name" | "amount" | "type" | "value"

因此,您希望key参数是其中之一。现在,假设您有一个有效的密钥,例如"amount"。然后,您可以像以下那样查找该键的属性类型:

type ItemAmount = Item["amount"];
// type ItemAmount = number

因此,对于K类型的key参数,您都希望value参数为Item[K]


因此,针对您的函数类型的第一枪可能是这样的:

function patch(item: Item, key: keyof Item, value: Item[keyof Item]): Item {
    return {
        ...item,
        [key]: value
    };
}

declare const item: Item;
patch(item, 7, false); // error! 7 is not a key, false is not a value

那更好,但是:

patch(item, "name", 14); // no error 

问题在于您使用的特定key与您通过的value之间没有关联。由于"name" some 键,而number some 可接受的值(对于"amount"),因此它不会出错。

解决此问题的方法是使key成为generic类型的K,比更具体(或“扩展”){{1 }},然后约束keyof Item键入value

Item[K]

这就是我的建议。希望能有所帮助;祝你好运!