Reputation: 64789
What type name does Typescript use to denote a variable in the form of "{}"?
This is probably super obvious to most, but I'm new to Typescript and I'm converting some Javascript, and this basic question is surprisingly difficult to google. All the other basic types are well documented, but I can't find anything for the basic hash type. I'm not sure if it's "object" or "Object" or "Map" or "any".
Upvotes: 3
Views: 3942
Reputation: 875
For all intents and purposes* the empty object type ({}
) is interchangeable with the Object
type. All values that have properties (i.e. aren't null
or undefined
) can be assigned to Object
or {}
.
The object
type on the other hand is for all non-primitive values, and thus isn't interchangeable with Object
or {}
.
The Map<KeyType, ValueType>
type specifically denotes a Map object.
And finally any
literally means any value: it can be a primitive or not, null, or undefined and anything I neglected to list here.
See Difference between 'object' ,{} and Object in TypeScript for more.
Even though they exist in TypeScript, you most likely don't actually want to use {}
or Object
in your code, there's a specific eslint rule for typescript that gives more details about this:
When you type a value as {}
, it'll warn you with: don't use {}
as a type. {}
actually means "any non-nullish value".
Record<string, unknown>
instead.unknown
instead.Record<string, never>
instead.And when using Object
: don't use Object
as a type. The Object
type actually means "any non-nullish value", so it is marginally better than unknown
.
Record<string, unknown>
instead.unknown
instead.* The empty object type and the Object
type actually differ in their compile time semantics: the built-in methods (like .toString()
) aren't type-checked for {}
but are checked for Object
Upvotes: 3
Reputation: 1074929
{}
is an object literal. Object literals in TypeScript can define nearly any kind of object. An empty object literal as in your example (literally {}
) is equivalent to type Object
. But an object literal with properties in it defines a possibly-anonymous type for an object with those properties, not just Object
. (See this answer that Emma Koskinen linked in their answer for more about {}
, Object
, and object
.)
One of the keys to understanding TypeScript's type system is that it's structural (based on the shape of things), not nominal (based on the names of things). For example:
interface Example {
a: number;
b: string;
}
function fn(x: Example) {
console.log(x.a, x.b);
}
const obj = {a: 42, b: "Life, the Universe, and Everything"};
fn(obj); // <=== No error here
Nothing says that obj
is of type Example
, but that's fine, because it's assignment-compatible with Example
, so passing it to fn
is perfectly fine.
In fact, we can go even further, and explicitly say that obj
is a different type:
interface Example {
a: number;
b: string;
}
function fn(x: Example) {
console.log(x.a, x.b);
}
interface AnotherExample {
a: number;
b: string;
c: boolean;
}
const obj: AnotherExample = {a: 42, b: "Life, the Universe, and Everything", c: true};
fn(obj); // <=== No error here
There, we've explicitly said that obj
is of type AnotherExample
, which is (slightly) different from Example
. But it's still just fine to pass it to fn
, because all that fn
requires is that the object have Example
's shape (a: number; b: string;
), and obj
does. It has an excess property c
, but that doesn't matter to fn
. fn
has said it only care about a
and b
.
Upvotes: 1