Typescript编译器未强制执行相关泛型

Typescript编译器未强制执行相关泛型,typescript,generics,typescript-generics,Typescript,Generics,Typescript Generics,考虑以下示例: 接口类型{ 新(…args:any):T; } 接口保持器{ 数据:T } 类StringHolder实现了StringHolder{ 构造函数(公共数据:字符串){}; } 类BooleanHolder实现Holder{ 构造函数(公共数据:布尔){}; } 类伪布尔持有者{ 数据=真; } 函数接受(类别:类型,数据:T){ console.log(clazz,data); } //预期:好的 接受(StringHolder,'text'); 接受(BooleanHolder

考虑以下示例:

接口类型{
新(…args:any):T;
}
接口保持器{
数据:T
}
类StringHolder实现了StringHolder{
构造函数(公共数据:字符串){};
}
类BooleanHolder实现Holder{
构造函数(公共数据:布尔){};
}
类伪布尔持有者{
数据=真;
}
函数接受(类别:类型,数据:T){
console.log(clazz,data);
}
//预期:好的
接受(StringHolder,'text');
接受(BooleanHolder,false);
//应为:编译错误
接受(StringHolder,true);
接受(BooleanHolder,'text')
//应为:编译错误
//实际:好的
//为什么编译器不强制执行“E扩展持有者”?

//这里T是布尔值,因此,E应该是类型,将结构类型放在一边,以限制
数据
参数与传递的
持有者
构造函数中的
数据
类型相同:

function acceptHolderClassAndData<T, H extends new (...args: any[]) => Holder<T>>(clazz: H, data: T): void {
    console.log(clazz, data);
}

acceptHolderClassAndData(StringHolder, 'str') // OK
acceptHolderClassAndData(BooleanHolder, true) // OK

acceptHolderClassAndData(StringHolder, true) // Error
acceptHolderClassAndData(BooleanHolder, 123) // Error
函数接受器ClassandData Holder>(类别:H,数据:T):无效{
console.log(clazz,data);
}
acceptHolderClassAndData(StringHolder,'str')//确定
acceptHolderClassAndData(BooleanHolder,true)//确定
acceptHolderClassAndData(StringHolder,true)//错误
acceptHolderClassAndData(BooleanHolder,123)//错误

TypeScript的类型系统是结构化的(您称之为“duck”),因此从概念上讲,您尝试执行的操作不受支持。您可以通过向类中添加一些不太可能被复制的结构来模拟命名类型,但是您能退一步解释一下为什么要这样做吗
FakeBooleanHolder
是一个
Holder
,根据TypeScript和我在示例代码中看到的内容。具体来说,如果您允许在需要
Holder
的情况下接受
FakeBooleanHolder
,会出现什么问题?@jcalz运行时duck类型绝对不会出错。我想看看我是否能让编译器抱怨
FakeBooleanHolder
。但是duck类型不是问题的主要关注点,函数
acceptHolderClassAndData
的签名是。我知道这让泛型走得太远了,但让我们假设我需要这样一个实现。假设函数是通过库公开的,我希望库的用户只传递
Holder
s,或者至少只传递duck类和它所保存的相同类型的数据。这里的“相同”是什么意思
true
被认为是
boolean
的一个子类型,因此
true
应该可以在任何需要
boolean
的地方使用。你担心写得不好吗?如果允许接受
FakeBooleanHolder
,您能否举例说明在
AcceptHolderClasssandData
中可能出现的错误?你真正的问题可能与变异和TypeScript在变异和子类型方面的不健全有关,但如果你不知道你要避免什么,我不能确定这是否是真正的问题。@jcalz我已经更新了这个问题。我希望现在更清楚了。感谢您的回复。为什么编译器没有强制执行“E扩展持有者”—它是强制执行的,
FakeBooleanHolder
在结构上与
Holder
兼容,谢谢。我已经更新了问题,我使用了一个
类型
界面。