Typescript 如何设置泛型约束以确保两种类型之间的公共键也具有相同的值类型?
我正在创建一个将字段从一个对象复制到另一个对象的函数,我想保证:Typescript 如何设置泛型约束以确保两种类型之间的公共键也具有相同的值类型?,typescript,typescript-generics,Typescript,Typescript Generics,我正在创建一个将字段从一个对象复制到另一个对象的函数,我想保证: 我只能给出两个对象之间共用的键 给定的键对应于两种类型中的相同值类型 如何实现第二个约束?这是我到目前为止所拥有的 函数copyField(输入:T1,输出:T2,键:keyof T1和keyof T2){ const keyValue=输入[键] output[key]=keyValue//如何确保两者的键值相同? //^Error:类型“T1[keyof T1&keyof T2]”不能分配给类型“T2[keyof T1&k
- 我只能给出两个对象之间共用的键
- 给定的键对应于两种类型中的相同值类型
函数copyField(输入:T1,输出:T2,键:keyof T1和keyof T2){
const keyValue=输入[键]
output[key]=keyValue//如何确保两者的键值相同?
//^Error:类型“T1[keyof T1&keyof T2]”不能分配给类型“T2[keyof T1&keyof T2]”。
//类型“T1”不可分配给类型“T2”。“T2”可以用
//与“T1”无关的任意类型。
}
类型A={field:string}
类型B={field:string}
文案
更新
下面的答案让我更接近我想要的,但仍然不能保证给定键的值完全相同。这说明了不匹配的类型仍然可以编译,因为约束只保证类型存在于两个对象上的某个位置,而不一定存在于给定的键上
函数copyField(输入:{[k in k]:V},输出:{[k in k]:V},键:k){
const keyValue=输入[键]
输出[键]=键值
}
类型A={s:string,不匹配:string}
类型B={s:string,不匹配:number}
//^---这些没有相同的类型
常数a:a={s:'hello',不匹配:'hello'}
常量b:b={s:'world',不匹配:123}
//这可以编译,但我希望它只接受's'
copyField(a、b,‘不匹配’)
尝试这样做
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
}
copyField({field: 'hello'}, {field: 'world'}, 'field')
函数copyField(输入:{[k in k]:V},输出:{[k in k]:V},键:k){
const keyValue=输入[键]
输出[键]=键值
}
copyField({field:'hello'},{field:'world'},'field'})
尝试这样做
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
}
copyField({field: 'hello'}, {field: 'world'}, 'field')
函数copyField(输入:{[k in k]:V},输出:{[k in k]:V},键:k){
const keyValue=输入[键]
输出[键]=键值
}
copyField({field:'hello'},{field:'world'},'field'})
这里有一个解决方案:
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]
type commonkey={
[K-in-keyof-S和keyof-T]:
[S[K],T[K]]扩展了[T[K],S[K]]?K:从不
}[科学和技术的关键]
它首先构造一个映射对象类型,如{s:'s',mismatch:never}
,然后将其映射到's'| never
,当然是's'
如果[S[K],T[K]]扩展了[T[K],S[K]
,则每个键K
都包括在内,这将检查S[K]
和T[K]
是否是彼此的子类型,即相同的类型。如果这对于您想要的太严格,您可以将其更改为S[K]extends T[K]
,以仅检查输入值类型是否可分配给输出值类型
这里有一个解决方案:
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]
type commonkey={
[K-in-keyof-S和keyof-T]:
[S[K],T[K]]扩展了[T[K],S[K]]?K:从不
}[科学和技术的关键]
它首先构造一个映射对象类型,如{s:'s',mismatch:never}
,然后将其映射到's'| never
,当然是's'
如果[S[K],T[K]]扩展了[T[K],S[K]
,则每个键K
都包括在内,这将检查S[K]
和T[K]
是否是彼此的子类型,即相同的类型。如果这对于您想要的太严格,您可以将其更改为S[K]extends T[K]
,以仅检查输入值类型是否可分配给输出值类型
如果这很重要,下面是我的想法:
function copyField<O, K extends keyof O, I extends Record<K, O[K]>>(
input: I,
output: O,
key: K
) {
const i: Record<K, O[K]> = input;
output[key] = i[key];
}
请注意,此处的错误不会出现在键
的“bad”
值上,而是出现在输入
参数上。在这种情况下,它特别警告坏
属性是字符串
,但不能将字符串
写入数字
属性
同样,上述定义将允许您从窄类型写入宽类型,但反之亦然:
copyField({ x: 123 }, { x: Math.random() < 0.5 ? 456 : "789" }, "x"); // okay
copyField({ x: Math.random() < 0.5 ? 456 : "789" }, { x: 123 }, "x"); // error!
// -------> ~
// Type 'string | number' is not assignable to type 'number'
copyField({x:123},{x:Math.random()<0.5?456:“789”},x”);//可以
copyField({x:Math.random()<0.5?456:“789”},{x:123},“x”);//错误!
// -------> ~
//类型“string | number”不可分配给类型“number”
第一行之所以有效,是因为可以安全地将input
中的number
值复制到output
中较宽的number |字符串中。但第二行有问题,因为您无法安全地将number |字符串
值从input
复制到output
中较窄的number
值。警告解释了这一点
如果这很重要,下面是我的想法:
function copyField<O, K extends keyof O, I extends Record<K, O[K]>>(
input: I,
output: O,
key: K
) {
const i: Record<K, O[K]> = input;
output[key] = i[key];
}
请注意,此处的错误不会出现在键
的“bad”
值上,而是出现在输入
参数上。在这种情况下,它特别警告坏
属性是字符串
,但不能将字符串
写入数字
属性
同样,上述定义将允许您从窄类型写入宽类型,但反之亦然:
copyField({ x: 123 }, { x: Math.random() < 0.5 ? 456 : "789" }, "x"); // okay
copyField({ x: Math.random() < 0.5 ? 456 : "789" }, { x: 123 }, "x"); // error!
// -------> ~
// Type 'string | number' is not assignable to type 'number'
copyField({x:123},{x:Math.random()<0.5?456:“789”},x”);//可以
copyField({x:Math.random()<0.5?456:“789”},{x:123},“x”);//错误!
// -------> ~
//类型“string | number”不可分配给类型“number”
第一行之所以有效,是因为可以安全地将input
中的number
值复制到output
中较宽的number |字符串中。但第二行有问题,因为您无法安全地将number |字符串
值从input
复制到output
中较窄的number
值。警告解释了这一点
虽然我认为这会奏效,但我