Typescript: prevent assignment of object with more properties than is specified in target interface

The other answers here are essentially correct: types in TypeScript are generally open/extendable and can always have properties added; that is, they are not exact types in which only known properties are allowed to exist. TypeScript doesn't really support exact types in general, although it does treat the types of freshly created object literals as exact types via excess property checks, as you've noticed.

If you really want to forbid a particular property key from a type in TypeScript, you can do this by making the property optional and have its type be never or undefined:

interface IUserSansPassword {
  username: string;
  email: string;
  password?: never; // cannot have a password
}

declare class UserSansPassword implements IUserSansPassword {
  username: string;
  email: string;
  password?: never; // need to declare this also
}

Now UserSansPassword is known not to have a defined password property. Of course now the following is an error:

interface IUser extends IUserSansPassword { // error! 
// Types of property "password" are incompatible
  password: string;
}

You can't extend IUserSansPassword by adding a password... if A extends B then you can always use an A instance where a B instance is expected. What you can do is extend a related type, your original IUserSansPassword, which can be computed using the Omit helper type:

interface IUser extends Omit<IUserSansPassword, "password"> {
  password: string;
}

declare class User implements IUser {
  username: string;
  email: string;
  password: string;
}

And then the following is an error like you expect:

const userSansPassword: UserSansPassword = new User();
// error, mismatch on "password" prop

Okay, hope that helps; good luck!

Link to code

Tags:

Typescript