我正在创建一个函数来将字段从一个对象复制到另一个对象,我想保证:
- 我只能给出两个对象通用的键
- 给定的键在两种类型中对应相同的值类型
如何实现第二个约束?这是我目前所拥有的。
function copyField<T1, T2>(input: T1, output: T2, key: keyof T1 & keyof T2) {
const keyValue = input[key]
output[key] = keyValue // How can I ensure that the key value is the same for both?
// ^ Error: Type 'T1[keyof T1 & keyof T2]' is not assignable to type 'T2[keyof T1 & keyof T2]'.
// Type 'T1' is not assignable to type 'T2'. 'T2' could be instantiated with an
// arbitrary type which could be unrelated to 'T1'.
}
type A = { field: string }
type B = { field: string }
copyField<A, B>({field: 'hello'}, {field: 'world'}, 'field')
Live example on typescriptlang.org
更新
下面的答案让我更接近我想要的,但仍然不能保证给定键的值完全相同。这演示了不匹配的类型如何仍然可以编译,因为约束只保证类型存在于两个对象上somewhere,不一定针对给定的键。
function copyField<K extends string, V>(input: {[k in K]: V}, output: {[k in K]: V}, key: K) {
const keyValue = input[key]
output[key] = keyValue
}
type A = { s: string, mismatch: string }
type B = { s: string, mismatch: number }
// ^--- these don't have the same type
const a: A = {s: 'hello', mismatch: 'hello'}
const b: B = {s: 'world', mismatch: 123}
// This compiles, but I want it to only accept 's'
copyField(a, b, 'mismatch')
最佳答案
这里有一个解决方案:
type CommonKeys<S, T> = {
[K in keyof S & keyof T]:
[S[K], T[K]] extends [T[K], S[K]] ? K : never
}[keyof S & keyof T]
它的工作原理是首先构造一个映射对象类型,如 {s: 's', mismatch: never}
,然后将其映射到 's' | never
当然是 的
。
如果 [S[K], T[K]] 扩展了 [T[K], S[K]]
,则包含每个键 K
,这会检查S[K]
和 T[K]
是彼此的子类型,即同一类型。如果这对于您想要的过于严格,您可以将其更改为 S[K] extends T[K]
以仅检查输入值类型是否可分配给输出值类型。
关于typescript - 如何设置通用约束以确保两种类型之间的公共(public)键也具有相同的值类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65042182/