Is there a way to get TypeScript's checker to simplify out unnecessary elements of intersection types, or am I wrong that they are unnecessary?
IIUC, the type SubType & SuperType
is equivalent to SubType
, but typescript does not seem to perform that simplification.
As seen below, I define a class Sub
as a declared sub-type of both class Base
and interface I
.
I then define generic functions for each super-type that takes a <T>
and if it's a passes a guard for that super-type, returns T &
SuperType.
I'd expect that T &
SuperType would simplify to T
because every T is a SuperType but the type checker does not do that simplification.
interface I {
readonly isI: true
}
class Base {
// HACK: Having a private member forces nominal typing
private readonly isBase: true = true;
toString() {
// Use the private field to quiet warning.
return `isBase=${this.isBase}`;
}
}
class Sub extends Base implements I {
readonly isI: true = true
}
// Custom type guards.
function isI(x: unknown): x is I {
return typeof x === 'object' && x !== null && 'isI' in x &&
(x as ({['isI']: unknown}))['isI'] === true;
}
function isBase(x: unknown): x is Base {
return x instanceof Base;
}
// Intersect with an inferred type parameters.
function andI<T>(x: T): T & I {
if (isI(x)) {
return x;
} else {
throw new Error();
}
}
function andBase<T>(x: T): T & Base {
if (isBase(x)) {
return x;
} else {
throw new Error();
}
}
let sub = new Sub();
let subAndI = andI(sub); // Has type (Sub & I)
let subAndBase = andBase(sub); // Has type (Sub & Base)
// Sub and (Sub&I) are mutually assignable
let sub2: Sub = subAndI;
subAndI = sub2;
The TS playground compiles this without errors nor warnings.
That let sub2: Sub = subAndI
seems to pass suggests to me that
But the type inferences (in the ".D.TS" tab) include:
declare let sub: Sub;
declare let subAndI: Sub & I;
declare let subAndBase: Sub & Base;
not, as I expected
declare let sub: Sub;
declare let subAndI: Sub;
declare let subAndBase: Sub;
Sub&I
seems mutually assignable with Sub
but is there some risk in treating the two as equivalent types in TS?