TypeScript未标记不兼容的泛型
我正在构建一个可插入的接口/类体系结构,以便“输出”可以插入“输入”。我很快发现,当我使用兼容的接口,但使用不兼容的泛型时,TypeScript不会抛出任何警告或错误。是否有我做错了的事情,或者我可以做更多的事情来强制进行正确的检查,或者这根本不受支持?打字稿2.9.2TypeScript未标记不兼容的泛型,typescript,class,generics,types,interface,Typescript,Class,Generics,Types,Interface,我正在构建一个可插入的接口/类体系结构,以便“输出”可以插入“输入”。我很快发现,当我使用兼容的接口,但使用不兼容的泛型时,TypeScript不会抛出任何警告或错误。是否有我做错了的事情,或者我可以做更多的事情来强制进行正确的检查,或者这根本不受支持?打字稿2.9.2 interface IValueA { fooA(): void; } interface IValueB { barB(): void; } interface ISomethingA<T> { g
interface IValueA {
fooA(): void;
}
interface IValueB {
barB(): void;
}
interface ISomethingA<T> {
goToB(thing: ISomethingB<T>): void;
}
interface ISomethingB<T> {
goToA(thing: ISomethingA<T>): void;
}
interface ISomethingAS extends ISomethingA<string> {}
interface ISomethingAN extends ISomethingA<number> {}
interface ISomethingBS extends ISomethingB<string> {}
interface ISomethingBN extends ISomethingB<number> {}
export class SomethingA<T> implements ISomethingA<T> {
public goToB(thing: ISomethingB<T>): void {
console.log("SomethingA", "goToB", thing);
}
}
export class SomethingAN implements ISomethingAN {
public goToB(thing: ISomethingBN): void {
console.log("SomethingA", "goToB", thing);
}
}
export class SomethingAS implements ISomethingAS {
public goToB(thing: ISomethingBS): void {
console.log("SomethingA", "goToB", thing);
}
}
export class SomethingB<T> implements ISomethingB<T> {
public goToA(thing: ISomethingA<T>): void {
console.log("SomethingA", "goToA", thing);
}
}
export class SomethingBN implements ISomethingBN {
public goToA(thing: ISomethingAN): void {
console.log("SomethingA", "goToA", thing);
}
}
export class SomethingBS implements ISomethingBS {
public goToA(thing: ISomethingAS): void {
console.log("SomethingA", "goToA", thing);
}
}
const a = new SomethingA<IValueA>();
const b = new SomethingB<IValueB>();
const as = new SomethingAS();
const an = new SomethingAN();
const bs = new SomethingBS();
const bn = new SomethingBN();
a.goToB(b); // ISomethingA<IValueA> expects ISomethingB<IValueA> but accepts ISomethingB<IValueB>
as.goToB(bn); // ISomethingAS (ISomethingA<string>) expects ISomethingBS (ISomethingB<string>) but accepts ISomethingBN (ISomethingB<number>)
an.goToB(bs); // ISomethingAN (ISomethingA<number>) expects ISomethingBN (ISomethingB<number>) but accepts ISomethingBS (ISomethingB<string>)
接口IValueA{
fooA():void;
}
接口IValueB{
倒钩():空洞;
}
界面等距{
goToB(thing:isothingb):无效;
}
界面等距{
goToA(事物:等轴物):空虚;
}
接口ISomethingAS扩展ISomethingA{}
接口ISomethingAN扩展ISomethingA{}
接口ISomethingBS扩展ISomethingB{}
接口ISomethingBN扩展ISomethingB{}
导出类SomethingA实现了ISomethingA{
公共goToB(thing:isothingb):无效{
log(“SomethingA”,“goToB”,thing);
}
}
导出类SomethingAN实现了ISomethingAN{
公共goToB(thing:isothingbn):无效{
log(“SomethingA”,“goToB”,thing);
}
}
导出类SomethingAS实现了ISomethingAS{
公共goToB(thing:isothingbs):无效{
log(“SomethingA”,“goToB”,thing);
}
}
导出类SomethingB实现了ISomethingB{
公共goToA(thing:isothinga):无效{
log(“SomethingA”,“goToA”,thing);
}
}
导出类SomethingBN实现ISomethingBN{
公共goToA(thing:isothingan):无效{
log(“SomethingA”,“goToA”,thing);
}
}
导出类SomethingBS实现了ISomethingBS{
公共goToA(thing:isothingas):无效{
log(“SomethingA”,“goToA”,thing);
}
}
常数a=新事物a();
常数b=新事物b();
const as=新事物as();
const an=新事物();
const bs=新事物bs();
const bn=新事物bn();
a、 goToB(b);//ISomethingA期望ISomethingB,但接受ISomethingB
as.goToB(bn);//ISomethingAS(ISomethingA)期望ISomethingBS(ISomethingB),但接受ISomethingBN(ISomethingB)
A.goToB(bs);//ISomethingAN(ISomethingA)期望ISomethingBN(ISomethingB),但接受ISomethingB(ISomethingB)
如果需要错误,实际上应该对ISomethingA
和ISomethingB
中的某些内容使用通用T
参数。如果只将其作为另一个泛型参数传递给其他对象,而从未实际使用过它,则不会出现错误,因为类型系统是结构化的,并且类型是兼容的
如中所述:“一般来说,您不应该有未使用的类型参数。该类型将具有意外的兼容性(如图所示),并且在函数调用中也无法进行正确的泛型类型推断。”
以下代码给出了您可能预期的错误:
interface IValueA {
fooA(): void;
}
interface IValueB {
barB(): void;
}
interface ISomethingA<T> {
goToB(thing: ISomethingB<T>): void;
t: T[];
}
interface ISomethingB<T> {
goToA(thing: ISomethingA<T>): void;
t: T[];
}
interface ISomethingAS extends ISomethingA<string> {}
interface ISomethingAN extends ISomethingA<number> {}
interface ISomethingBS extends ISomethingB<string> {}
interface ISomethingBN extends ISomethingB<number> {}
export class SomethingA<T> implements ISomethingA<T> {
public goToB(thing: ISomethingB<T>): void {
console.log("SomethingA", "goToB", thing);
}
t = [];
}
export class SomethingAN implements ISomethingAN {
public goToB(thing: ISomethingBN): void {
console.log("SomethingA", "goToB", thing);
}
t = [];
}
export class SomethingAS implements ISomethingAS {
public goToB(thing: ISomethingBS): void {
console.log("SomethingA", "goToB", thing);
}
t = [];
}
export class SomethingB<T> implements ISomethingB<T> {
public goToA(thing: ISomethingA<T>): void {
console.log("SomethingA", "goToA", thing);
}
t = [];
}
export class SomethingBN implements ISomethingBN {
public goToA(thing: ISomethingAN): void {
console.log("SomethingA", "goToA", thing);
}
t = [];
}
export class SomethingBS implements ISomethingBS {
public goToA(thing: ISomethingAS): void {
console.log("SomethingA", "goToA", thing);
}
t = [];
}
const a = new SomethingA<IValueA>();
const b = new SomethingB<IValueB>();
const as = new SomethingAS();
const an = new SomethingAN();
const bs = new SomethingBS();
const bn = new SomethingBN();
a.goToB(b); // error
as.goToB(bn); // error
an.goToB(bs); // error
接口IValueA{
fooA():void;
}
接口IValueB{
倒钩():空洞;
}
界面等距{
goToB(thing:isothingb):无效;
t:t[];
}
界面等距{
goToA(事物:等轴物):空虚;
t:t[];
}
接口ISomethingAS扩展ISomethingA{}
接口ISomethingAN扩展ISomethingA{}
接口ISomethingBS扩展ISomethingB{}
接口ISomethingBN扩展ISomethingB{}
导出类SomethingA实现了ISomethingA{
公共goToB(thing:isothingb):无效{
log(“SomethingA”,“goToB”,thing);
}
t=[];
}
导出类SomethingAN实现了ISomethingAN{
公共goToB(thing:isothingbn):无效{
log(“SomethingA”,“goToB”,thing);
}
t=[];
}
导出类SomethingAS实现了ISomethingAS{
公共goToB(thing:isothingbs):无效{
log(“SomethingA”,“goToB”,thing);
}
t=[];
}
导出类SomethingB实现了ISomethingB{
公共goToA(thing:isothinga):无效{
log(“SomethingA”,“goToA”,thing);
}
t=[];
}
导出类SomethingBN实现ISomethingBN{
公共goToA(thing:isothingan):无效{
log(“SomethingA”,“goToA”,thing);
}
t=[];
}
导出类SomethingBS实现了ISomethingBS{
公共goToA(thing:isothingas):无效{
log(“SomethingA”,“goToA”,thing);
}
t=[];
}
常数a=新事物a();
常数b=新事物b();
const as=新事物as();
const an=新事物();
const bs=新事物bs();
const bn=新事物bn();
a、 goToB(b);//错误
as.goToB(bn);//错误
A.goToB(bs);//错误