Is there a way to make this not compile? (because it does...)
const bar: { a: string } = {
a: '',
...{b: ''}
}
Is there a way to make this not compile? (because it does...)
const bar: { a: string } = {
a: '',
...{b: ''}
}
I was shocked to find that this passed the type checker!
After poking around a bit, I have a strong hunch about why this is occurring, but I haven't found any official word to back it up yet. As such, this isn't an answer, but a conversation-starter that's too long for a comment. That's all to say, take what follows with a grain of salt.
I suspect that TypeScript's "ascription"/"annotation" mechanism allows for some wiggle-room based on subtypes. Specifically, when we write:
const foo: Foo = bar;
as long as bar's type is a subtype of Foo, this seems to pass the checker with flying colors.
Here's a specific example:
class Foo {
public a: string;
}
// `Bar` is a subtype of `Foo`
class Bar extends Foo {
public b: string;
}
const foo: Foo = new Bar();
// ^^^ ^^^ This is just fine!
Furthermore, since TypeScript's notion of subtyping is "structural", the following is also perfectly acceptable:
class Foo {
a: string;
}
// `Quux` is structurally the same as (and therefore a subtype of) `Foo`
class Quux {
a: string;
}
const foo: Foo = new Quux();
With this [theory] in mind, your example is accepted by the checker because { a: string; b: string } is a subtype of { a: string }.
In conclusion, if this is correct, I don't think there is a way to coax the type checker into rejecting your example.
Edit: This isn't the complete story. As @apflieger points out, this theory doesn't explain why
const foo: { a: string } = {
a: 'test',
b: 'test',
};
is rejected. It appears as though the spreading is critical here.
It could be that the type of
{
a: 'test',
...{ b: 'test' }
}
is inferred as something like { a: string } & { b: string }, whereas in the previous case it is inferred as { a: string; b: string }.