Typescript's excess property check limitations
Tags: typescript, javascript, beginners
Published: 2021-02-26 08:21:41

---
title: Typescript's excess property check limitations
published: true
description: Typescript can be confusing. Let's try to make it a little bit less confusing by understanding when the excess property check works, and when it does not. 
tags: #typescript #javascript #beginner
//cover_image: https://direct_url_to_image.jpg
---

# The obvious

In Typescript, when we are trying to assign an object literal to a typed variable, it is reasonable to expect Typescript to check whether there are any extra properties that are not defined in the respective type. 

```typescript
interface Doggo {
  name: string;
  likesTreatos: boolean;
}

const max: Doggo = {
  name: 'Max',
  likesTreatos: true,
  age: 4
  /**
  Type '{ name: string; likesTreatos: true; age: number; }'
  is not assignable to type 'Doggo'.
  Object literal may only specify known properties, and 'age'
  does not exist in type 'Doggo'
  */
}
``` 

# The not so obvious 


Alright, let's tweak that piece of code a little bit and see how Typescript reacts. 

```typescript
interface Doggo {
  name: string;
  likesTreatos: boolean;
}

const dog = {
  name: 'Max',
  likesTreatos: true,
  age: 4
}

const max: Doggo = dog // no errors
```

Wait a second, the value of `dog` that we are trying to assign to our `max` is not so different than before, yet Typescript doesn't think that's an issue this time. 

# The triggers of the `excess property check`

Typescript does not complain because there is no *excess property check* triggered. The reason why is because it will only trigger on assignments that involve object literals, and `dog` is clearly not one. 

On the first example above, our `max` variable was actually assigned to an object literal, triggering the check which then threw an error. 

We can see a similar behavior when passing function parameters.

```typescript
interface Doggo {
  name: string;
  likesTreatos: boolean;
}

function giveSnack(doggo: Doggo) {
  console.log(`Snack given to ${doggo.name}`)
}

giveSnack({
  name: 'Max',
  likesTreatos: true,
  age: 4
  /**
  Argument of type '{ name: string; likesTreatos: true; age: number; }'
  is not assignable to parameter of type 'Doggo'.
  Object literal may only specify known properties, and 'age'
  does not exist in type 'Doggo'
  */
})

const dog = {
  name: 'Max',
  likesTreatos: true,
  age: 4
}

giveSnack(dog) // no errors
```

# But still, why would that not fail..?

It was hard for me to initially accept the fact that Typescript would allow an assignment like that. 
But actually, as far as Typescript's structural type system is concerned, this is a totally valid scenario. 

Let's take a step back. 

```typescript
interface Doggo {
  name: string;
  isGoodBoy?: boolean;
}
```

How big is the domain of values for the `Doggo` type?
The answer is, pretty huge! 
Basically any object that has a `name` property that is a string and **any** other property besides a non-boolean `isGoodBoy` is a valid Doggo.

Based on that, here is a surprisingly valid assignment to a `Doggo` typed constant:

```typescript
interface Doggo {
  name: string;
  isGoodBoy?: boolean;
}

const max: Doggo = window
```

`window` has a `name` property which is a string and does not have a non-boolean `isGoodBoy` property (even though it'd be cool).

# Going back to our previous example

```typescript
interface Doggo {
  name: string;
  likesTreatos: boolean;
}

const dog = {
  name: 'max',
  likesTreatos: true,
  age: 4
}

const max: Doggo = dog // no errors
```

This starts to make a bit more sense now, the variable `dog` is inferred as `{name: string, likesTreatos: boolean, age: number}` which is included in the domain of values of the type `Doggo` and hence being a valid assignment.
On top of that, the excess property check is not triggered because we are not dealing with object literals.

# Final thoughts
One could say that Typescript's structural type checker focuses more on preventing us from writing code that would throw errors during runtime, while the excess property checking tries to identify code which might not be what we intended.