Typescript 可以为有区别的联合编写类型安全函数,其中输入是对象,其键是其对应值的区别
是否可以为区分的联合类型编写以下Typescript 可以为有区别的联合编写类型安全函数,其中输入是对象,其键是其对应值的区别,typescript,Typescript,是否可以为区分的联合类型编写以下sum函数 第一个arg=标记是一个判别式 第二个arg=对象,其键=鉴别器(应等于值[tag])和值是来自鉴别器并集的形状之一 例如: //如何为成员的键添加限制,使key=A[K][tag] const sum=(标记:T)=>(成员:{[K in keyof A]:A[K]})=>{ // ... 抛出新错误(“”) } 类型形状={kind:'圆';半径:数字}{kind:'正方形';x:number} //应该编译 总和(“种类”)({ 圆:{种类:
sum
函数
- 第一个arg=
是一个判别式标记
- 第二个arg=
,其对象
=键
(应等于鉴别器
)和值[tag]
是来自鉴别器并集的形状之一值
//如何为成员的键添加限制,使key=A[K][tag]
const sum=(标记:T)=>(成员:{[K in keyof A]:A[K]})=>{
// ...
抛出新错误(“”)
}
类型形状={kind:'圆';半径:数字}{kind:'正方形';x:number}
//应该编译
总和(“种类”)({
圆:{种类:'圆',半径:10},
正方形:{种类:'square',x:10}
})
//不应编译,因为平方对其相应值不是正确的判别式
总和(“种类”)({
正方形:{种类:'圆',半径:10},
圆:{种类:'圆',半径:10}
})
是的,可以这样做-但是您需要为联合体提供一个通用类型。如果不为此类型传递参数,则在提供错误属性时TS不可能出错,因为它没有任何可验证的内容
所以看起来像这样:
type StringProperties={[key-in-keyof-O]:O[key]扩展字符串?key:never}[keyof-O];
类型ExtractByTag<
O扩展对象,//要从中提取的对象联合
K扩展StringProperties,//要使用的键
P、 //要提取的属性值
>=O扩展了{[输入K]:P}?O:从来没有;
常量和=(标记:T)=><
O扩展{[key in T]:string},
>(成员:{[key in S[T]]:ExtractByTag})=>{
返回成员;
}
但这并不是很好,因为现在必须显式地优化函数中的类型,以实际执行任何有用的操作,并实现如何执行这些操作,例如:
const isShapesByKey=<
P扩展StringProperties,//“种类”
S扩展{[key in P]:任意}//形状扩展{P:K}
>(key:P,arg:unknown):arg是ShapeKinds=>{
//在这里,您将编写自定义逻辑,以确定成员是否具有某种形状
返回true;
}
常量和=(标记:T)=><
O扩展{[key in T]:string},
>(成员:{[key in S[T]]:ExtractByTag})=>{
if(isShapesByKey(“种类”,成员)){
const circle=members.circle;
const square=members.square;
//用形状做东西
}
返回成员;
}
这完全失去了通用性的好处。在这一点上,您不妨编写一个不太通用、更简单的版本:
type ExtractShape=S扩展了{kind:K}?S:从来没有;
const sum=(成员:{[key in Shape['kind']]:ExtractShape})=>{
const circle=members.circle;
const square=members.square;
}
因此,如果你想走一般路线,我建议你提供一个函数,选择要求和的值。这样,您也可以删除泛型参数,只需为属性选择函数提供一个更简洁的参数:
type StringProperties={[key-in-keyof-O]:O[key]扩展字符串?key:never}[keyof-O];
类型ExtractByTag<
O扩展对象,//要从中提取的对象联合
K扩展StringProperties,//要使用的键
P、 //要提取的属性值
>=O扩展了{[输入K]:P}?O:从来没有;
常量和=(标记:T)=><
O扩展{[key in T]:string},
>(
成员:{[key in O[T]]:ExtractByTag},
属性选择器:(extractFrom:O)=>number
) => {
返回Object.values(成员).reduce((上一个,下一个)=>{
返回上一个+属性选择器(下一个);
}, 0);
})
//用法
总和(“种类”)({
圆:{种类:'圆',半径:10},//确定
square:{kind:'square',x:10},//好的
},(形状:形状)=>{
开关(形状、种类){
案例“循环”:
返回形状。半径;
“方形”案例:
返回形状.x;
}
});
//不应编译,因为平方对其相应值不是正确的判别式
总和(“种类”)({
square:{kind:'square',x:10},//好的
圆:{kind:'circle',x:10},//错误
},(形状:形状)=>{
开关(形状、种类){
案例“循环”:
返回形状。半径;
“方形”案例:
返回形状.x;
}
});
是的,可以这样做-但是您需要为联合体提供一个通用类型。如果不为此类型传递参数,则在提供错误属性时TS不可能出错,因为它没有任何可验证的内容
所以看起来像这样:
type StringProperties={[key-in-keyof-O]:O[key]扩展字符串?key:never}[keyof-O];
类型ExtractByTag<
O扩展对象,//要从中提取的对象联合
K扩展StringProperties,//要使用的键
P、 //要提取的属性值
>=O扩展了{[输入K]:P}?O:从来没有;
常量和=(标记:T)=><
O扩展{[key in T]:string},
>(成员:{[key in S[T]]:ExtractByTag})=>{
返回成员;
}
但这并不是很好,因为现在必须显式地优化函数中的类型,以实际执行任何有用的操作,并实现如何执行这些操作,例如:
const isShapesByKey=<
P扩展StringProperties,//“种类”
S扩展{[key in P]:任意}//形状扩展{P:K}
>(key:P,arg:unknown):arg是ShapeKinds=>{
//在这里,您将编写自定义逻辑,以确定成员是否具有某种形状
返回true;
}
常量和=(标记:T)=><
O扩展{[key in T]:string},
>(成员:{[key in S[T]]:ExtractByTag})=>{
if(isShapesByKey(“种类”,成员)){
const circle=members.circle;
const square=members.square;
//用形状做东西
}
返回成员;
}
这完全失去了通用性的好处。在这一点上,您不妨编写一个不太通用、更简单的版本:
type ExtractShape=S扩展了{kind:K}?S:n