如何定义一个按名称交换两个对象属性值并检查类型兼容性的 Typescript 函数?
How to define a Typescript function that swaps values of two object properties by name, with check of type compatibility?
我正在尝试定义一个函数,该函数在给定名称的情况下交换对象上两个属性的值,但我希望编译器检查类型兼容性(或至少检查两个属性是否具有相同类型):
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
我得到了以下结果,但它需要传递两次 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
或者,如果我 return 一个函数,我可以使用条件类型实现期望的结果,但是很容易忘记第二次调用。
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
是否可以简化上述示例?我可以提供某种类型而不是 never
来指示类型系统错误吗?
P.S。我知道 [obj.a, obj.b] = [obj.b, obj.a];
,但想避免它。
好的,他们的密钥原来是用高级类型过滤第二个密钥。
可用的源代码:https://github.com/IKoshelev/ts-typing-util/blob/master/src/Swap.ts
NPM 安装npm i ts-typing-util
export type SwappableKeys<T, TKey1 extends keyof T> = Exclude<{
[key in keyof T]:
/**/ T[key] extends T[TKey1]
/**/ ? T[TKey1] extends T[key]
/* */ ? key
/* */ : never
/**/ : never;
}[keyof T], TKey1>;
/**
* Swap prop values with a check that values have compatible type
* @example
* const t = {
* a: 1,
* b: 2,
* c: '',
* c1: '',
* d: { a: 5 },
* e: { a: 6 },
* f: { b: 7 },
* g: { a: '' }
* }
*
* swap(t, 'a', 'b');
* swap(t, 'a', 'c'); //error
* swap(t, 'b', 'c'); //error
* swap(t, 'a', 'a'); //error
* swap(t, 'c', 'c1');
* swap(t, 'd','e');
* swap(t, 'd','f'); //error
* swap(t, 'd','g'); //error
**/
export function swap<T, TKey1 extends keyof T>(inst: T, key1: TKey1, key2: SwappableKeys<T, TKey1>): void {
const buff = inst[key1] as any;
inst[key1] = inst[key2] as any;
inst[key2] = buff;
}
我正在尝试定义一个函数,该函数在给定名称的情况下交换对象上两个属性的值,但我希望编译器检查类型兼容性(或至少检查两个属性是否具有相同类型):
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
我得到了以下结果,但它需要传递两次 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
或者,如果我 return 一个函数,我可以使用条件类型实现期望的结果,但是很容易忘记第二次调用。
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
是否可以简化上述示例?我可以提供某种类型而不是 never
来指示类型系统错误吗?
P.S。我知道 [obj.a, obj.b] = [obj.b, obj.a];
,但想避免它。
好的,他们的密钥原来是用高级类型过滤第二个密钥。
可用的源代码:https://github.com/IKoshelev/ts-typing-util/blob/master/src/Swap.ts
NPM 安装npm i ts-typing-util
export type SwappableKeys<T, TKey1 extends keyof T> = Exclude<{
[key in keyof T]:
/**/ T[key] extends T[TKey1]
/**/ ? T[TKey1] extends T[key]
/* */ ? key
/* */ : never
/**/ : never;
}[keyof T], TKey1>;
/**
* Swap prop values with a check that values have compatible type
* @example
* const t = {
* a: 1,
* b: 2,
* c: '',
* c1: '',
* d: { a: 5 },
* e: { a: 6 },
* f: { b: 7 },
* g: { a: '' }
* }
*
* swap(t, 'a', 'b');
* swap(t, 'a', 'c'); //error
* swap(t, 'b', 'c'); //error
* swap(t, 'a', 'a'); //error
* swap(t, 'c', 'c1');
* swap(t, 'd','e');
* swap(t, 'd','f'); //error
* swap(t, 'd','g'); //error
**/
export function swap<T, TKey1 extends keyof T>(inst: T, key1: TKey1, key2: SwappableKeys<T, TKey1>): void {
const buff = inst[key1] as any;
inst[key1] = inst[key2] as any;
inst[key2] = buff;
}