Typescript - 如何键入函数以确保两个属性的键具有相同的属性类型

问题描述 投票:0回答:2

我有以下打字稿功能(针对这个问题进行了简化):

function assign<T1,T2>(o1:T1,k1:keyof T1, o2:T2, k2:keyof T2){
    o1[k1] = o2[k2];
}

我想确保

o1[k1]
的数据类型与
o2[k2]
的数据类型相同。这意味着该函数仅允许在可以分配值的情况下组合属性名称。示例:

let a = {foo: 'hello', version: 10};
let b = {bar: 'bye'};
assign(a, 'foo',b, 'bar'); // This should be allowed as both properties are strings
assign(a, 'version',b, 'bar'); // This should give a type error as the properties have different types

我尝试使用映射类型等,但无法找到正确工作的解决方案。 例如:

function assign<T1,T2>(o1:T1,k1:keyof T1, o2:T2,
           k2:T1[K1] extends T2[K2]?keyof T2:never){
    o1[k1] = o2[k2];
}

但这不起作用。有什么想法吗?

typescript types
2个回答
0
投票

您可以尝试根据第一个对象的值输入第二个对象:

function assign<Obj1 extends {}, Key1 extends keyof Obj1, Key2 extends string>(o1: Obj1, k1: Key1, o2: {[k in Key2]: Obj1[Key1]}, k2: Key2) {
    o1[k1] = o2[k2];
}

let a = {foo: 'hello', version: 10};
let b = {bar: 'bye'};
assign(a, 'foo', b, 'bar'); // Ok
assign(a, 'version', b, 'bar'); // Error: Argument of type '{ bar: string; }' is not assignable to parameter of type '{ bar: number; }'.

0
投票

您首先需要使用泛型推断两个参数的确切键类型。然后您可以使用

T2[K2] extends T1[K1] ? K2
简单地比较其值类型。如果第二个键的值可以分配给第一个键,那么一切都很好。否则,我们使用
never
来引发编译器错误。

declare function assign<T1, K1 extends keyof T1, T2, K2 extends keyof T2>(
  o1: T1,
  k1: K1,
  o2: T2,
  k2: T2[K2] extends T1[K1] ? K2 : never,
): unknown;

let a = { foo: "hello", version: 10 };
let b = { bar: "bye" };
assign(a, "foo", b, "bar");
assign(a, "version", b, "bar");
//                      ~~~~~
// Argument of type 'string' is not assignable to parameter of type 'never'.

TypeScript 游乐场

© www.soinside.com 2019 - 2024. All rights reserved.