When we use a class as a type, only keys of that class should be allowed. Anyway, when assigning [Symbol()]
, [String()]
or [Number()]
as property key no error is given, allowing wrong properties to be assigned. One even more curious case is that if [Symbol()]
is assigned to a variable before being used as a prop key, it does error as expected while the same doesn't happen if we assign [String()]
or [Number()]
to a variable before being used.
const sym = Symbol()
const str = String('another unwanted prop')
const num = Number(1)
class A { // <-- can be class/type/interface
a?: string
b?: number
}
let a: A = {
[Symbol()]: 'anything',
[String('unwanted prop')]: 'anything',
[Number(0)]: 'anything',
[str]: 'anything',
[num]: 'anything',
[sym]: 'anything' // <-- why does this error while [Symbol()], [String()] and [Number()] don't?
// ~~~~~~~~~~~~~~~~~
}
This doesn't looks like expected behaviour to me and I find it a bit confusing.
Is this an issue or the desired behaviour? Am I missing something?
This is (apparently) considered a missing feature of TypeScript; computed property names don't generally trigger excess property warnings, unless the type of the computed property name is a single literal type (like "abc"
) or a unique symbol
type (like a named declaration const x = Symbol()
).
See microsoft/TypeScript#22427 which was marked as a bug but closed as "fixed" without actually being fixed, and microsoft/TypeScript#36920, a re-reporting of that issue which is still open but classified as a feature request instead of a bug. So, it's a known issue, but it's more "intended" than "bug".
Excess property checking is more of a linter feature than a type safety feature. Object types in TypeScript are open/extendible and not closed/sealed/exact; having excess properties shouldn't break an object type. See Use explicit properties of an object which is type annotated for more information on why excess properties aren't actually prohibited according to the type system.
The reason why excess property warnings happen at all is to prevent people from accidentally throwing away information; if you write const foo: {x: string} = {x: "hello", y: 123}
, the compiler warns you about y
because you won't be able to access y
on foo
later on, and so you've apparently added a property that gets thrown away... and that might be a mistake. Excess property warnings are more like a "did you mean to do this?" message and less like a "this will cause runtime errors" warning.
All this is to say that there are places where the compiler could issue the warning but does not. But reports of these are generally treated like suggestions and feature requests, as the absence of the warning is an inconvenience and not a type safety hole. For example, see microsoft/TypeScript#20863, asking for excess property warnings on non-discriminated union types.