Chapters

  • 0. Introduction

    Free

  • 1. Types & Values

    Free

  • 2. Types are just data

    Free

  • 3. Objects & Records

    Free

  • 4. Arrays & Tuples

    Free

  • 5. Conditional Types
  • 6. Loops with Recursive Types
  • 7. Template Literal Types
  • 8. The Union Type Multiverse
  • 9. Loops with Mapped Types
  • 10. Assignability Quiz
  • 11. Designing Type-Safe APIs
  • 12. Conclusion

Articles

Subscribe

About

Made with ❤️ by @GabrielVergnaud

|Chapters|Articles

What's the difference between object and {} in TypeScript?

— by Gabriel Vergnaud · Sep 10, 2023

I used to think that object was an alias for the {} "empty object" type in TypeScript, but I was wrong! These two types represent different sets of values, and if you want to write accurate type definitions for your functions and classes, it's important to know which one to choose.

Let's see how they differ!

The {} empty object type

The empty object {} type is one of the largest sets of values. All types with properties or methods are assignable to it, including primitive types, like number, string and boolean!

The empty object set

The empty object set contains objects and primitive types.

This implies that a function taking {} will happily accept most values:

function fn(something: {}) {
  /*                   👆
            The empty object type!       */
}

// ✅ these type-check:
fn({ token: "..." });
fn({});
fn("Hi!");
fn(1337);
fn(() => "a function!");
function fn(something: {}) {
  /*                   👆
            The empty object type!       */
}

// ✅ these type-check:
fn({ token: "..." });
fn({});
fn("Hi!");
fn(1337);
fn(() => "a function!");

Only two values aren't assignable to the empty object: null and undefined.

fn(null);
fn(undefined);
fn(null);
fn(undefined);

This is the only difference between {} and unknown by the way. unknown contains every single JavaScript value, including null and undefined:

The unknown type.

unknown contains everything.

The object type

Now let's look at the object type. Unlike {}, object does not include primitive types!

The empty object set

The object set.

Here is what happens if you try assigning a primitive type like a string or a number to object:

let a: object;

a = 403; // ❌
a = "⛔️"; // ❌
a = { some: "object" }; // ✅
let a: object;

a = 403; // ❌
a = "⛔️"; // ❌
a = { some: "object" }; // ✅

It doesn't type-check!

But what about functions and arrays?

let b: object;

// ✅
b = [1, 2, 3];
b = (n: number) => n.toString();
let b: object;

// ✅
b = [1, 2, 3];
b = (n: number) => n.toString();

They are assignable to the object type too. Only primitive types aren't.

Which one should you use?

When writing functions taking objects, you usually want to use the object type. For example, consider the following merge function:

const merge = <
  A extends {},
  B extends {}
>(a: A, b: B): A & B => ({
  ...a,
  ...b,
});

It won't throw if you give it a string or a number, but the result will look pretty weird:

const result = merge(42, "what?"); // type-checks
// => {0: 'w', 1: 'h', 2: 'a', 3: 't', 4: '?'}

Is this really what you expected? Probably not.

If you constrain your type parameters with object instead of {}, passing numbers or strings will simply not type-check:

const merge = <A extends object, B extends object>(a: A, b: B): A & B => ({
  ...a,
  ...b,
});

const result = merge(42, "what?"); // ❌
const merge = <A extends object, B extends object>(a: A, b: B): A & B => ({
  ...a,
  ...b,
});

const result = merge(42, "what?"); // ❌

No one will ever mistakenly pass a string to your merge function again! 🎉

Summary 📚

Here are the main takeaways from this article:

  • Types are sets of values.
  • {} includes all primitive types.
  • object does not.

The behavior of the {} type isn't super intuitive, so my advice is to use the object type unless you really know what you are doing!

If you liked this article, chances are you'll like Type-Level Typescript. It's an advanced TypeScript course that will give you a solid understanding of the type system's fundamentals and guide you through its most advanced features. Enroll Now!

Subscribe to the newsletter!

Receive all new chapters and articles from Type-Level TypeScript directly in your inbox!

?:
:

Only receive Type-Level TypeScript content. Unsubscribe anytime.