Skip to Content
Course content

145: Excess Property Checks

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I want to show you something that trips up almost every developer when they start getting comfortable with TypeScript's structural typing. You know the rule: as long as an object has the required properties, TypeScript is usually happy, even if it has a few extra ones. But there's a specific scenario where TypeScript suddenly becomes a strict bouncer at the door.

Wait, why is this an error?

Let's look at a simple scenario. I'm building a system to handle user profiles, and I have a function that just prints out a welcome message based on a user's name and email.

interface User {
  name: string;
  email: string;
}

function welcomeUser(user: User) {
  console.log(`Welcome, ${user.name}! We'll contact you at ${user.email}.`);
}

Now, I've got a user object that has a bit more data than the interface requires—maybe it came from a database and includes their age. I'll try to pass it directly into the function:

welcomeUser({
  name: "Alice",
  email: "alice@example.com",
  age: 30 // Error: Object literal may only specify known properties
});

This is where I usually stop and blink. I'm thinking, "Wait, the User interface requires a name and an email. I provided both. Who cares if I also provided the age?" According to everything we've learned about structural typing, this should be fine. But TypeScript is throwing a red squiggly line under age.

The loophole

I suspect this is just a specific check for object literals. To test this, I'll try to "hide" the object in a variable first. Instead of passing the object directly into the function call, I'll assign it to a constant and then pass that constant.

const userWithAge = {
  name: "Alice",
  email: "alice@example.com",
  age: 30
};

welcomeUser(userWithAge); // No error!

Now it works. No errors, no warnings. The exact same data is being passed into the exact same function, but because I moved the object into a variable first, TypeScript stopped complaining. This feels like a bug or a weird inconsistency, but it's actually a very intentional feature called "Excess Property Checks."

The logic behind the madness

Think about why TypeScript does this. When you pass an object literal directly into a function, you are explicitly saying, "I am creating this object specifically for this purpose."

If I accidentally typed emial instead of email, and TypeScript just ignored the extra property, I'd be passing an object that's missing a required field while carrying a useless typo. By being strict with object literals, TypeScript is essentially saying: "You're creating this on the fly; are you sure you didn't make a typo?"

However, when you use a variable, TypeScript assumes the object might have been created elsewhere—perhaps by a library or a API response—and as long as it satisfies the minimum requirements of the User interface, it's safe to use. It prioritizes flexibility over strictness once the object exists independently of the function call.

My rule of thumb? If you're seeing this error, it's usually a signal to double-check your spelling. If you actually want the object to have extra properties that the function doesn't care about, you can either use the variable approach I used above, or you can use a type assertion like as User, though I generally prefer the variable route because it's cleaner.




📋 Practical Task

Refactoring the Product Inventory Guard

You are working on an e-commerce tool. You have a Product interface and a function logProductDetails that expects it. However, your team is currently passing "raw" product objects from a JSON file directly into the function, and TypeScript is blocking the build because the JSON objects contain extra metadata (like internalId and warehouseLocation) that aren't in the Product interface.

Your Task:

  • Create a Product interface with title (string) and price (number).
  • Create a function logProductDetails(product: Product) that logs the title and price.
  • Attempt to call logProductDetails using an object literal that includes title, price, and internalId. Observe the error.
  • Fix the error by implementing the "variable loophole" discussed in the lesson, ensuring the object is assigned to a constant before being passed to the function.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.