It's not a compiler bug; it's a set of features that you are not intending to use.
First, in interface
and other purely type-level object type definitions, the compiler interprets a comma (,
) as a separator between members, just like a semicolon (;
):
// the following interfaces are equivalent
interface Semicolons { foo: string; bar: number; }
interface Commas { foo: string, bar: number }
That means 'nolife'
is considered the end of the Type
member declaration.
Second, you are allowed to put property names inside quotation marks:
// the following two interfaces are equivalent
interface Bare { foo: string }
interface Quoted { "foo": string }
This is helpful when an object type has a property that isn't a valid JavaScript identifier, like "uses-dashes"
or even just to be consistent with JSON specifications.
That means YouDidNotDeclare
is considered to be the name of a property.
Finally, TypeScript does not require type annotations. For variable or function parameters declared without explicit type annotations, sometimes there is enough contextual information for the compiler to infer a reasonable type for them:
const foo = { a: 123 };
// foo inferred as { a: number; }
[1, 2, 3].map(x => x * 3);
// x inferred as number
Such implicit types are often quite desirable and it's considered good practice for you to leave off type annotations in situations like this where the inferred types are what you intended.
But there are other situations in which there is not enough contextual information for reasonable type inference. When this happens, the compiler gives up and infers the any
"type":
// the following two interfaces are equivalent
interface Explicit { foo: any }
interface Implicit { foo }
Thus your interface
is equivalent to the following:
export interface Hater {
Name: string;
Bio?: string;
Type: 'casual' | 'pro' | 'titan' | 'nolife';
YouDidNotDeclare: any;
Online: boolean;
}
which is definitely not what you intended.
In fact, it is so rarely useful for the compiler to implicitly infer an any
type like it does with YouDidNotDeclare
, that there's a recommended compiler option --noImplicitAny
which produces a compiler warning whenever this happens. This compiler option can be enabled by itself, or along with a whole suite of stronger type checking options via the --strict
compiler option.
If you enable those, your interface definition will immediately warn you that something weird has happened:
Type: 'casual' | 'pro' | 'titan' | 'nolife', 'YouDidNotDeclare'; // error!
// ----------------------------------------> ~~~~~~~~~~~~~~~~~~
// Member ''YouDidNotDeclare'' implicitly has an 'any' type.
Which should allow you to fix the definition to the version you intended it to be.
Playground link to code