I want to write two mixin classes, Foo and Bar. Bar requires access to the protected interface of Foo. Therefore I use TS2.8 conditional types to extract the type of a Foo class and use this type as a generic constraint for the Bar mixin's Base class.
Unfortunately, this causes mysteriously inconsistent "conflicting declaration" errors. Why? Is this a TS bug? Can I work around it?
/*
* Why is this type error happening?
* Class 'Composed' incorrectly extends base class 'Bar...
* Type 'Composed' is not assignable to type 'Bar...
* Property '_referenceToEmptyInterface' has conflicting declarations and is inaccessible in type 'Composed'.
*/
class Composed extends BarMixin(FooMixin(EventEmitter)) {}
import { EventEmitter } from "events";
type Constructor<I = {}> = new (...args: any[]) => I;
interface EmptyInterface {}
/** Mixin */
function FooMixin<C extends Constructor>(Base: C) {
return class extends Base {
private _referenceToEmptyInterface: EmptyInterface = {}; // Causes the error. Why?
private _fooPrivate: number = 0; // Does not cause an error. Why not, given the above?
protected _fooProtected: number = 0;
}
}
/** Type of class that creates instances of type Foo */
type FooConstructor = typeof FooMixin extends (a: Constructor) => infer Cls ? Cls : never;
/** Mixin that can only extend subclasses of Foo */
function BarMixin<C extends FooConstructor>(Base: C) {
return class extends Base {
barMethod() {
// We require `Base` to implement `Foo` because we need access to protected `Foo` properties.
this._fooProtected++;
}
}
}
_referenceToEmptyInterface is flagged as a duplicate declaration. However, _fooPrivate is not. The only difference is that the former's type refers to an interface declaration, whereas the latter's type is a primitive. The interface declaration is totally empty and is declared outside of the mixin function, so all declarations of _referenceToEmptyInterface should be identical.
Is this a bug in the compiler? How should I handle this situation?
EDIT: related GH issue: https://github.com/Microsoft/TypeScript/issues/22845