Cerin
Cerin

Reputation: 64789

What type name does Typescript use for {}?

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

Answers (2)

Emma
Emma

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".

  • If you want a type meaning "any object", you probably want Record<string, unknown> instead.
  • If you want a type meaning "any value", you probably want unknown instead.
  • If you want a type meaning "empty object", you probably want 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.

  • If you want a type meaning "any object", you probably want Record<string, unknown> instead.
  • If you want a type meaning "any value", you probably want 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

T.J. Crowder
T.J. Crowder

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

Playground link

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

Playground link

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

Related Questions