When experimenting with the type system, the `declare` keyword becomes handy for mocking values, but in real production code, its usage is minimal.
declare name: string;
This informs the compiler:
"There exists a property named `name` of type `string`. I don't need to prove its existence, but I want to utilize it anyway."
The `declare` keyword is commonly found in type definition files that offer typings for situations where Typescript cannot derive type information (like in plain JS files). Therefore, if encountered in your code, one might assume that `name` is being added dynamically from a JS file and documented here.
But assumptions could be incorrect.
name!: string;
This signals to the compiler:
"There's a property named `name` with a type of `string | undefined`. Initially set as `undefined`, however, treat it always as a `string` during access or assignment."
By using this pattern, it explicitly states that `name` starts as undefined but is handled as a string throughout. This implies that its initial setup may not be inside the constructor.
Your clarification confirms these assumptions.
In practice, within this specific case, the outcomes are nearly identical. In both scenarios, you possess an uninitialized string property. Nevertheless, arguments can be made that `name!: string` offers better clarity on what's happening.
Furthermore, it's crucial to note that `declare` does not produce any executable code; it simply establishes something in the type system. (Kudos to @NoelDeMartin for pointing this out)
class Foo {
bar!: string;
declare baz: string;
}
let bar: string
declare let baz: string
Compilation yields:
class Foo {
constructor() {
Object.defineProperty(this, "bar", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
}
let bar;
Note that `baz` is entirely omitted from the output.
Ultimately, it's advisable to refactor your code so that property assignment occurs within the constructor. Both approaches mentioned are less stringent in terms of type safety as handling an uninitialized value as a `string` might lead to unexpected runtime errors.