Typescript 基于泛型的类字段的类型
想象一下下面的代码():Typescript 基于泛型的类字段的类型,typescript,generics,union-types,Typescript,Generics,Union Types,想象一下下面的代码(): 类型AvailableType={ “数组”:数组 更新 (更新至) 应该可以根据类型属性键入检查值: //在包装类中,应该可以使用,因为只有当类型为“array”时,值才能是数组: 公共值(val:未知){ if(this.type=='array'){ 这个.value.push(val); } } 基本问题是,泛型类型参数没有通过控制流分析缩小范围,这在TypeScript中是一个相当长期的开放问题,有关更多信息,请参阅 当您在开关/大小写语句中选中类型时
类型AvailableType={
“数组”:数组
更新
(更新至)
应该可以根据类型
属性键入检查值
:
//在包装类中,应该可以使用,因为只有当类型为“array”时,值才能是数组:
公共值(val:未知){
if(this.type=='array'){
这个.value.push(val);
}
}
基本问题是,泛型类型参数没有通过控制流分析缩小范围,这在TypeScript中是一个相当长期的开放问题,有关更多信息,请参阅
当您在开关
/大小写
语句中选中类型
时,编译器可以将类型
变量的类型缩小为文本类型数组
,但它不会将类型参数T
缩小为数组
。因此,编译器无法验证是否可以安全地分配任何变量[]
类型可用类型[T]
的值。编译器必须执行一些当前没有执行的分析,例如“好的,如果类型==”数组“
,我们从类型推断T
,然后在这个案例
块中,我们可以将T
缩小到”数组“
,因此this.value
的类型是AvailableTypes[“array”]
,也就是说,any[]
,因此将[]
分配给它是安全的。”但这不会发生
同样的问题也会导致“值
未明确分配”错误。编译器没有必要的资金来查看开关
/案例
是否用尽了t
的所有可能性,因为它在这里不进行控制流分析
这里最简单的解决方法是告诉编译器您知道自己在做什么,因为它无法验证
要处理穷尽性问题,您可以创建一个抛出的缺省值
案例,如下所示:
class Wrapper<T extends keyof AvailableTypes> {
private readonly type: T;
private readonly value: AvailableTypes[T];
constructor(type: T) {
this.type = type;
switch (type) {
case 'array':
this.value = [] as AvailableTypes[T]; // assert
break;
case 'string':
this.value = '' as AvailableTypes[T]; // assert
break;
case 'object':
this.value = {} as AvailableTypes[T]; // assert
break;
default:
throw new Error("HOW DID THIS HAPPEN"); // exhaustive
}
}
}
另一个解决方法()是利用这样一个事实:如果您有一个t
类型的值t
,并且一个k类型的键k
扩展了t
的键,那么t[k]
的类型将被编译器视为t[k]
。因此,如果我们可以创建一个有效的AvailableType
,我们可以使用类型
对其进行索引。可能如下所示:
class Wrapper<T extends keyof AvailableTypes> {
private readonly type: T
private readonly value: AvailableTypes[T];
constructor(type: T) {
this.type = type;
const initValues: AvailableTypes = {
array: [],
string: "",
object: {}
};
this.value = initValues[type];
}
}
类包装器{
私有只读类型:T
私有只读值:AvailableType[T];
建造师(类型:T){
this.type=type;
常量初始值:AvailableType={
阵列:[],
字符串:“”,
对象:{}
};
this.value=initValues[type];
}
}
这是一种比类型断言和switch
语句更好的方法,而且启动时是相当类型安全的
好的,希望其中一个能帮上忙。祝你好运
更新:谢谢你的详细回答!但是当我试图检查类型
是否为数组
,并尝试将某些内容推入值时,它失败了:(即使type
基本上严格地绑定到value属性……我在问题中看不到这一点;我错过了吗?或者这是一个单独的问题还是后续问题?a总是很有帮助。祝你好运!对不起,我已经更新了问题-type
属性实际上是用于此目的的!问题是一样的,我看到的唯一没有完全重构的解决方案是类型断言:(this.value as AvailableTypes[“array”]).push(val);
。如果我知道您计划在包装器的实现中进行这样的操作,我建议您使用一个有区别的联合,而不是使用类或使用一系列子类(联合的每个成员有一个子类).我在答案的底部添加了一个游乐场链接,显示了与兄弟班的歧视性结合可能比单一普通班更有效。祝你好运!
class Wrapper<T extends keyof AvailableTypes> {
private readonly type: T
private readonly value: AvailableTypes[T];
constructor(type: T) {
this.type = type;
const initValues: AvailableTypes = {
array: [],
string: "",
object: {}
};
this.value = initValues[type];
}
}