Closed
Description
Bug Report
Adding an implementation of an interface allows an invalid assignability check of the interface to pass
🔎 Search Terms
assignability, unnecessary implementation
🕗 Version & Regression Information
- This changed between versions 3.7.5 and 3.8.3
It's still present in all versions including nightly.
⏯ Playground Link
Playground link with relevant code
Thanks @MartinJohns for the link
💻 Code
interface Parent<A, B> {
getChild(): Child<A, B>;
iter(): Iterable<Parent<A, B>>;
}
interface Child<A, B>
extends Parent<A, B> {
readonly a: A;
readonly b: B;
}
class Impl<A, B> implements Parent<A, B> {
constructor(readonly child: Child<A, B>) {
}
getChild(): Child<A, B> {
return this.child;
}
*iter(): Iterable<Parent<A, B>> {
const map = new Map<Child<unknown, unknown>, Child<A, B>[]>();
function* gen(
inp: Child<A, B>
): Iterable<Child<A, B>> {
yield* map.get(inp) || [];
}
}
}
const x: Parent<unknown, unknown> = {} as any;
const _: Parent<null, unknown> = x; // should not pass
The final assignment should not pass. It accurately errors in 3.7.5, if the Impl
class is removed (or any aspect of the iter
implementation is modified), or by adding a sentinel type like sentinel?: A
to the Parent
interface to aid in type checking.
🙁 Actual behavior
No error is thrown in the final assignment.
🙂 Expected behavior
A n error is throw:
Type 'Parent<unknown, unknown>' is not assignable to type 'Parent<null, unknown>'.
Type 'unknown' is not assignable to type 'null'.