我有以下界面:
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
使用什么?答案 0 :(得分:2)
由于值类型取决于,因此您应该使用通用类型参数。
结果:
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]
这就是我的建议。希望能有所帮助;祝你好运!