TypeScript Version: 3.6
Search Terms:
subtyping invariant covariant
| Read and write | variance |
| --- | --- |
| read and write | invariance |
| readonly | covariance |
| writeonly | contravariance |
Code
interface a {
foo?: string
}
interface b extends a {
foo: string // subtype of string | undefined
}
declare const b: b;
const a: a = b;
a.foo = undefined; // now b has property `foo:undefined`
console.log(b.foo);
Expected behavior:
Can't extends when property foo of b isn't readonly
Actual behavior:
It has no warning and no error
Playground Link:
Related Issues:
A not-so-great workaround at the moment is to just make all your properties readonly always, and treat everything as immutable.
I personally do that but it's unnerving that I can slip up and make a mistake, and not have the compiler tell me about it
I don't think we're likely to make extends sound with respect to variance. Many crusty old OO codebases violate it.
Intersection behaves better, so I'd recommend that over extends if you care about variance.
Doesn't TS add new breaking behavior behind a flag?
Anything that relies on unsound extends can turn it off, and everyone else that wants more safety, and are masochistic can use the new flag
I'm curious if anyone's run into issues in real code arising from this issue.
Most helpful comment
Doesn't TS add new breaking behavior behind a flag?
Anything that relies on unsound extends can turn it off, and everyone else that wants more safety, and are masochistic can use the new flag