Reputation: 27831
type Metadata = {
tags?: Set<string>;
};
const metadata: Metadata = {
tags: new Set<string>(),
};
metadata.tags.add('test'); // <-- Object is possibly 'undefined'.ts(2532)
But how? I've initialized it to new Set<string>
... ?
I assume because it is marked as nullable/optional in Metadata
, but I figured the compiler would see that I had indeed initialized tags
with a value.
Upvotes: 0
Views: 199
Reputation: 26296
When TypeScript evaluates your types, it works down your code, line by line, narrowing the type of the variable as it goes.
If you used:
const metadata = {
tags: new Set<string>(),
};
The type of this constant variable, is:
{
tags: Set<string>;
}
However, on that same line, you tell TypeScript, "no, this object is a Metadata
object - treat it as such" when you use:
const metadata: Metadata = {
tags: new Set<string>(),
};
So, by the time TypeScript gets to checking this line, metadata
is a Metadata
object, where the tags
property is optional:
metadata.tags.add('test'); // metadata.tags is possibly 'undefined'
Because you understand that you've just set this property, you can use the !
type assertion to say "this value is not undefined
or null
".
metadata.tags!.add('test');
If you plan to initialize each property in metadata
, you can mutate the type to say "this object follows the shape of Metadata
, but each property is required" using the Required<T>
utility type:
const metadata: Required<Metadata> = {
tags: new Set<string>(),
};
Which will allow you to use your assignment as normal:
metadata.tags.add('test');
Upvotes: 2