Я пытаюсь определить функцию, которая меняет значения двух свойств объекта по их именам, но я бы хотел, чтобы компилятор проверял совместимость типов (или, по крайней мере, проверял, чтобы оба свойства имели одинаковый тип):
function swap<T, TKey1 extends keyof T, TKey2 extends keyof T>(obj: T, key1: TKey1, key2: TKey2): void{
let temp = obj[key1];
obj[key1] = obj[key2];
obj[key2] = temp;
}
let obj = {
a: 1,
b: 2,
c: ""
}
swap(obj, "a", "b"); // good, both are numbers
swap(obj, "a", "c"); // should not compile, swapping number with string
Детская площадка TS
Я получил некоторый результат со следующим, но он требует, чтобы obj был пройден дважды.
function swap<T,
TKey1 extends keyof T,
TKey2 extends keyof T,
TIn extends { [p in TKey1|TKey2]: T[TKey1] } >(_:T, obj: TIn, key1: TKey1, key2: TKey2): void{
let temp = <any>obj[key1];
obj[key1] = <any>obj[key2];
obj[key2] = temp;
}
let obj = {
a: 1,
b: 2,
c: ""
}
swap(obj, obj, "a", "b"); // good, both are numbers
swap(obj, obj, "a", "c"); // error, as expected
Детская площадка TS
В качестве альтернативы, я могу достичь желаемого результата с условными типами, если я возвращаю функцию, но второй вызов слишком легко забыть.
function swap<T,
TKey1 extends keyof T,
TKey2 extends keyof T>(obj: T, key1: TKey1, key2: TKey2):
T[TKey1] extends T[TKey2] ? T[TKey2] extends T[TKey1]
? () => void
: never : never {
return <any>(() => {
let temp = <any>obj[key1];
obj[key1] = <any>obj[key2];
obj[key2] = temp;
});
}
let obj = {
a: 1,
b: 2,
c: ""
}
swap(obj, "a", "b")(); // good, both are numbers
swap(obj, "a", "c")(); // error, as expected
TS детская площадка
Можно ли упростить приведенные выше примеры?Могу ли я указать какой-либо тип вместо never
, который будет указывать на ошибку системы типов?
PS Я знаю о [obj.a, obj.b] = [obj.b, obj.a];
, но хотел бы избежать этого.