Reputation: 44376
Consider the following:
class X {
bar() {
return "bar"
}
constructor(private readonly x: number){}
}
interface Y extends X {
}
const f = (y: Y) => { console.log(y.bar()); }
f({ bar: () => "tavern"});
It does not compile, because x
is missing.
f({ bar: () => "tavern", x: 1});
does not compile because x
isn't private.
Re-writing the code so it's possible to declare the x
private
class Y implements X {
bar() {
return "tavern"
}
private x = 1;
}
is rejected because "types have separate declarations".
The only solution I have found is to remove the private
from the constructor.
What I'd really like to do is the first: I don't care about private properties of the class, and I especially don't care about private members declared within the constructor.
My two questions are:
Upvotes: 2
Views: 324
Reputation: 44376
Ryan Cavanaugh, development lead for the Typescript team at Microsoft, wrote:
Allowing the private fields to be missing would be an enormous problem, not some trivial soundness issue.
Consider this code:
class Identity { private id: string = "secret agent"; public sameAs(other: Identity) { return this.id.toLowerCase() === other.id.toLowerCase(); } } class MockIdentity implements Identity { public sameAs(other: Identity) { return false; } }
MockIdentity
is a public-compatible version ofIdentity
but attempting to use it as one will crash insameAs
when a non-mocked copy interacts with a mocked copy.
Which sucks. It makes perfect sense, but it sucks.
But I found a workaround that solves my problem:
type Public<T> = {
[P in keyof T]: T[P];
};
class X {
bar() {
return "bar"
}
constructor(private readonly x: number){}
}
interface Y extends Public<X> { }
const f = (y: Y) => { console.log(y.bar()); }
f({ bar: () => "tavern"});
This allows me to mock out complex types reliably, without having to also mock out private data.
This is safe in a test context, where mocked instances and real instances never interact.
Upvotes: 4