Ваш оригинальный код разрешит неудачный вызов patch
, как
declare const item: Item;
patch(item, 7, false); // no error ?
, несмотря на тот факт, что 7
не является действительным ключом свойства Item
, а false
не являетсядопустимое значение свойства для этого или любого ключа Item
.
Давайте рассмотрим ваш конкретный Item
интерфейс и посмотрим, что с ним делают keyof
и типы поиска .
Оператор типа keyof
принимает тип объекта и возвращает тип его ключей.Если у объекта нет индексной подписи , этот тип должен быть объединением литеральных типов , соответствующих его известным действительным ключам:
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"
- это некоторая клавиша, а number
- это некоторое допустимое значение (для "amount"
), то это не ошибка.
Способчтобы исправить это, нужно сделать key
a generic type K
, который может быть более конкретным, чем (или "extended") keyof Item
, а затем ограничить value
для вводаItem[K]
:
function patch<K extends keyof Item>(item: Item, key: K, value: Item[K]): 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); // error! 14 is not a string
patch(item, "name", "okay"); // works
patch(item, "amount", 14); // okay
Так вот, что я бы предложил.Надеюсь, это поможет;удачи!