Excess Property Checks
In our first example using interfaces, TypeScript let us pass { size: number; label: string; }
to something that only expected a { label: string; }
. We also just learned about optional properties, and how they’re useful when describing so-called “option bags”.
However, combining the two naively would let you to shoot yourself in the foot the same way you might in JavaScript. For example, taking our last example using createSquare
:
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { // ... } let mySquare = createSquare({ colour: "red", width: 100 });
Notice the given argument to createSquare
is spelled colour
instead of color
. In plain JavaScript, this sort of thing fails silently.
You could argue that this program is correctly typed, since the width
properties are compatible, there’s no color
property present, and the extra colour
property is insignificant.
However, TypeScript takes the stance that there’s probably a bug in this code. Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error.
// error: 'colour' not expected in type 'SquareConfig' let mySquare = createSquare({ colour: "red", width: 100 });
Getting around these checks is actually really simple. The easiest method is to just use a type assertion:
let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
However, a better approach might be to add a string index signature if you’re sure that the object can have some extra properties that are used in some special way. If SquareConfig
s can have color
and width
properties with the above types, but could also have any number of other properties, then we could define it like so:
interface SquareConfig { color?: string; width?: number; [propName: string]: any; }
We’ll discuss index signatures in a bit, but here we’re saying a SquareConfig
can have any number of properties, and as long as they aren’t color
or width
, their types don’t matter.
One final way to get around these checks, which might be a bit surprising, is to assign the object to another variable: Since squareOptions
won’t undergo excess property checks, the compiler won’t give you an error.
let squareOptions = { colour: "red", width: 100 }; let mySquare = createSquare(squareOptions);
Keep in mind that for simple code like above, you probably shouldn’t be trying to “get around” these checks. For more complex object literals that have methods and hold state, you might need to keep these techniques in mind, but a majority of excess property errors are actually bugs. That means if you’re running into excess property checking problems for something like option bags, you might need to revise some of your type declarations. In this instance, if it’s okay to pass an object with both a color
or colour
property to createSquare
, you should fix up the definition of SquareConfig
to reflect that.
Please login to continue.