Skip to content

Latest commit

 

History

History
129 lines (98 loc) · 5.64 KB

excess-property-checking.md

File metadata and controls

129 lines (98 loc) · 5.64 KB

Item 11: Distinguish Excess Property Checking from Type Checking

Things to Remember

  • When you assign an object literal to a variable with a known type or pass it as an argument to a function, it undergoes excess property checking.
  • Excess property checking is an effective way to find errors, but it is distinct from the usual structural assignability checks done by the TypeScript type checker. Conflating these processes will make it harder for you to build a mental model of assignability. TypeScript types are not "closed" (pass:[Item 4]).
  • Be aware of the limits of excess property checking: introducing an intermediate variable will remove these checks.
  • A "weak type" is an object type with only optional properties. For these types, assignability checks require at least one matching property.

Code Samples

interface Room {
  numDoors: number;
  ceilingHeightFt: number;
}
const r: Room = {
  numDoors: 1,
  ceilingHeightFt: 10,
  elephant: 'present',
// ~~~~~~~ Object literal may only specify known properties,
//         and 'elephant' does not exist in type 'Room'
};

💻 playground


const obj = {
  numDoors: 1,
  ceilingHeightFt: 10,
  elephant: 'present',
};
const r: Room = obj;  // OK

💻 playground


interface Options {
  title: string;
  darkMode?: boolean;
}
function createWindow(options: Options) {
  if (options.darkMode) {
    setDarkMode();
  }
  // ...
}
createWindow({
  title: 'Spider Solitaire',
  darkmode: true
// ~~~~~~~ Object literal may only specify known properties,
//         but 'darkmode' does not exist in type 'Options'.
//         Did you mean to write 'darkMode'?
});

💻 playground


const o1: Options = document;  // OK
const o2: Options = new HTMLAnchorElement();  // OK

💻 playground


const o: Options = { darkmode: true, title: 'Ski Free' };
                  // ~~~~~~~~ 'darkmode' does not exist in type 'Options'...

💻 playground


const intermediate = { darkmode: true, title: 'Ski Free' };
const o: Options = intermediate;  // OK

💻 playground


const o = { darkmode: true, title: 'MS Hearts' } as Options;  // OK

💻 playground


interface Options {
  darkMode?: boolean;
  [otherOptions: string]: unknown;
}
const o: Options = { darkmode: true };  // OK

💻 playground


interface LineChartOptions {
  logscale?: boolean;
  invertedYAxis?: boolean;
  areaChart?: boolean;
}
function setOptions(options: LineChartOptions) { /* ... */ }

const opts = { logScale: true };
setOptions(opts);
//         ~~~~ Type '{ logScale: boolean; }' has no properties in common
//              with type 'LineChartOptions'

💻 playground