Currently, I am in the process of constructing a pluggable interface/class system that enables an "output" to connect with an "input". To my surprise, TypeScript seems to overlook any warnings or errors that might arise when a compatible interface is paired with an incompatible generic. I am unsure if I am approaching this the wrong way, if there are additional steps I can take to enforce proper checking, or if this functionality is simply not supported in TypeScript 2.9.2.
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>)