Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 87a2cb5

Browse files
Merge pull request #148 from Microsoft/excessProperties
Added section on excess property checking
2 parents 8e18df5 + 04df042 commit 87a2cb5

File tree

1 file changed

+59
-2
lines changed

1 file changed

+59
-2
lines changed

pages/Interfaces.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ In TypeScript, interfaces fill the role of naming these types, and are a powerfu
99
The easiest way to see how interfaces work is to start with a simple example:
1010

1111
```ts
12-
function printLabel(labelledObj: {label: string}) {
12+
function printLabel(labelledObj: { label: string }) {
1313
console.log(labelledObj.label);
1414
}
1515

@@ -20,6 +20,7 @@ printLabel(myObj);
2020
The type-checker checks the call to `printLabel`.
2121
The `printLabel` function has a single parameter that requires that the object passed in has a property called `label` of type string.
2222
Notice that our object actually has more properties than this, but the compiler only checks that *at least* the ones required are present and match the types required.
23+
There are some cases where TypeScript isn't as lenient, which we'll cover in a bit.
2324

2425
We can write the same example again, this time using an interface to describe the requirement of having the `label` property that is a string:
2526

@@ -82,7 +83,7 @@ interface SquareConfig {
8283
width?: number;
8384
}
8485

85-
function createSquare(config: SquareConfig): {color: string; area: number} {
86+
function createSquare(config: SquareConfig): { color: string; area: number } {
8687
let newSquare = {color: "white", area: 100};
8788
if (config.color) {
8889
// Error: Property 'collor' does not exist on type 'SquareConfig'
@@ -97,6 +98,62 @@ function createSquare(config: SquareConfig): {color: string; area: number} {
9798
let mySquare = createSquare({color: "black"});
9899
```
99100

101+
# Excess Property Checks
102+
103+
In our first example using interfaces, TypeScript let us pass `{ size: number; label: string; }` to something that only expected a `{ label: string; }`.
104+
We also just learned about optional properties, and how they're useful when describing so-called "option bags".
105+
106+
However, combining the two naively would let you to shoot yourself in the foot the same way you might in JavaScript.
107+
For example, taking our last example using `createSquare`:
108+
109+
```ts
110+
interface SquareConfig {
111+
color?: string;
112+
width?: number;
113+
}
114+
115+
function createSquare(config: SquareConfig): { color: string; area: number } {
116+
// ...
117+
}
118+
119+
let mySquare = createSquare({ colour: "red", width: 100 });
120+
```
121+
122+
Notice the given argument to `createSquare` is spelled *`colour`* instead of `color`.
123+
In plain JavaScript, this sort of thing fails silently.
124+
125+
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.
126+
127+
However, TypeScript takes the stance that there's probably a bug in this code.
128+
Object literals get special treatment and undergo *excess property checking* when assigning them to other variables, or passing them as arguments.
129+
If an object literal has any properties that the "target type" doesn't have, you'll get an error.
130+
131+
```ts
132+
// error: 'colour' not expected in type 'SquareConfig'
133+
let mySquare = createSquare({ colour: "red", width: 100 });
134+
```
135+
136+
Getting around these checks is actually really simple.
137+
The best and easiest method is to just use a type assertion:
138+
139+
```ts
140+
let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig);
141+
```
142+
143+
Another approach, which might be a bit surprising, is to assign the object to another variable:
144+
145+
```ts
146+
let squareOptions = { colour: "red", width: 100 };
147+
let mySquare = createSquare(squareOptions);
148+
```
149+
150+
Since `squareOptions` won't undergo excess property checks, the compiler won't give you an error.
151+
152+
Keep in mind that for simple code like above, you probably shouldn't be trying to "get around" these checks.
153+
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.
154+
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.
155+
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.
156+
100157
# Function Types
101158

102159
Interfaces are capable of describing the wide range of shapes that JavaScript objects can take.

0 commit comments

Comments
 (0)