The comment provided at this link explains that TypeScript follows a structurally-typed approach.
This implies that when extending Derived
from Base
, it is not possible to exclude properties of Base
from Derived
.
However, by utilizing structural typing, you can create an additional type that remains compatible with Base
while excluding any "extra" properties present in Derived
. This can be achieved by defining them as optional properties of type never
(using certain type utilities), like so:
Take a look at the TS Playground for implementation details.
interface Base {
a: string;
}
interface Derived extends Base {
b: string;
}
const x: Derived = {
a: "a",
b: "b",
};
type PreventExtendedProps<Base, Derived extends Base> = Base & Partial<Record<Exclude<keyof Derived, keyof Base>, never>>;
type BaseNotDerived = PreventExtendedProps<Base, Derived>;
// Check the type's properties:
declare const b: BaseNotDerived;
b.a // string
b.b // undefined
// Example assignment scenario:
const y: BaseNotDerived = x; /*
^
Type 'Derived' cannot be assigned to type 'BaseNotDerived'.
Type 'Derived' cannot be assigned to type 'Partial<Record<"b", never>>'.
Properties of 'b' are incompatible.
Type 'string' cannot be assigned to type 'never'.(2322) */