The Omit
utility type simply eliminates a specified set of properties from the existing keys of an object type. However, objects in general can contain additional properties beyond those defined by their type. Object types are not "exact" (as discussed in microsoft/TypeScript#12936); if a key is not explicitly mentioned in a type, that property is considered unspecified or unknown rather than prohibited.
Otherwise, using extended interfaces would be impossible:
interface Foo {
x: string;
}
function processFoo(foo: Foo) {
console.log(foo.x.toUpperCase())
};
interface Bar extends Foo {
y: number
}
const bar: Bar = { x: "abc", y: 123 };
processFoo(bar); // Allowed because every Bar is also a Foo
In the example above, although Foo
does not include the y
property, it does not prevent Bar
from extending it. Omitting properties from a type expands its acceptance criteria rather than limiting it.
This means an IUSerModel
could still be a valid value of type
Omit<IUserModel, 'password'>
.
It is not possible to create a type that rejects all potential excess properties without exact types or some form of "rest index signature" as requested in microsoft/TypeScript#17867, among other features.
However, you can somewhat prohibit a specific excess property. You can define it as an optional property (allowing for its presence or absence) of the impossible never
type (making it incredibly difficult to exist). This approach closely resembles property prohibition, with some exceptions.
As a result, we can create our custom OmitAndProhibit
utility type that excludes certain properties and then reintroduces them as optional properties of type never
:
type OmitAndProhibit<T, K extends string> =
Omit<T, K> & { [P in K]?: never };
Let's demonstrate this concept:
type IUserDto = OmitAndProhibit<IUserModel, 'password'>
function createUser(user: IUserModel): IUserDto {
const newUser: IUserModel = {
fullname: user.fullname,
username: user.username,
password: user.password
}
return newUser; // Error!
// Type 'IUserModel' is not assignable to type '{ password?: undefined; }'.
}
The compiler correctly identifies the issue with newUser
having a string
-valued password
property when it expects an optional property of type never
. This aligns closely with prohibiting the property, albeit with certain edge cases to consider.
Click here to access the code on Playground