1. What is actually {} type in TypeScript? Does it really stand for "any non-nullish value" (I can't find confirmation in TypeScript documentation)?
If you do console.log(typeof(d));
then you will see that {}
is of type object
. This is not entirely correct but let me explain about object
first. First of all object
with lowercase o
can be any non-primitive value while Object
with uppercase O
can include any primitive value through Object.prototype
.
So if you try to overwrite object
with a primitive value it will give errors as it doesn't like primitive values, although null will work as is an object
type as well, undefined on the other hand is of type undefined but this can always be assigned.
Now {}
is called "Object literal" this is actually both object
and Object
. So that is why both primitive and non-primitive values are assignable to an object literal as mentioned on packt.
So normally any value can be assigned to an object literal, unless strictNullChecks is enabled as null and undefined cannot be assigned in this case as @RobbieSpeed mentioned in the comments.
You can check this in the following stackblitz, beware that strictNullChecks is not enabled here.
2. How should I actually type "empty object without any properties"?
There are probably a couple of ways to do this, the ones I know are you can either instantiate it like you did or do: let d = {};
as the type is automatically determined there is no need to add a type.
The other method is to use an interface to define your properties when they are known but make them all optional by adding question marks behind the property names.
This makes it easy to use aswell since all your properties are known and can be found by intellisense aswell.
Example:
export interface User {
name?: string;
email?: string;
}
let user: User = {};
user.name = "Joe";
user.email = "joe@hotmail.com";
If this didn't answer your question sufficiently, feel free to ask away!
Ps: for more information on objects check out 2ality
Update #1
As Paddokt mentioned in the comments if you want to type an object either as an empty object or only a specific object the above example won't work so to do this a different approach is required.
If you want the example above to be only either a User or an empty object you would have to wrap the user object inside a different object as following:
export interface optUser {
user?: User;
}
export interface User {
name: string;
email: string;
}
let optuser: optUser = {};
optuser.user = {
name: "Joe",
email: "joe@hotmail.com"
}
This way you can have a variable that is either an empty object or an object that contains a user where both name and email are required.
Note:
Do know that optuser.user = {};
won't work, either optuser has a user object or it doesn't have an object at all, as User itself can't be an empty object here.