Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Last active September 19, 2019 13:52
Show Gist options
  • Save OliverJAsh/1d073570b779fd1b97e50b9a52c812fa to your computer and use it in GitHub Desktop.
Save OliverJAsh/1d073570b779fd1b97e50b9a52c812fa to your computer and use it in GitHub Desktop.
TypeScript excess property checks: caveats and workarounds

TypeScript excess property checks: caveats and workarounds

https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks

Not checked when spreading

type MyObject = {
  foo: string;
  bar: string;
  baz: string;
};
type MyOtherObject = {
  foo: string;
};

declare const myObject: MyObject;

// Omit + rest
// Oops, we forgot to omit a prop (`baz`).
const { bar, ...restProps } = myObject;
const myOtherObject: MyOtherObject = {
  // No excess error :-(
  ...restProps
};

This is particularly problematic when spreading props into a React component, as it can hurt performance or create invalid HTML: microsoft/TypeScript#31798.

Workarounds

Instead of using "omit + rest" (above), "pick":

// Pick
const myOtherObject: MyOtherObject = {
  foo: myObject.foo,
  // Excess error :-)
  baz: myObject.baz
};

Not checked on empty object literals

type A = {};
const a: A = { a: 1 };

https://stackoverflow.com/questions/42537727/empty-interface-allow-any-object

Not checked on function return types

type Fn = () => {
  foo: string;
};
const fn: Fn = () => ({
  foo: "foo",
  // No excess error :-(
  bar: "bar"
});

microsoft/TypeScript#33507

Workarounds

Annotate function return type or use constructor

type FnResult = {
  foo: string;
};
type Fn = () => FnResult;
const fn: Fn = (): FnResult => ({
  foo: "foo",
  // Excess error :-)
  bar: "bar"
});

Not checked in unions, beware of runtime exceptions

The future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment