I have a database model (Mongo) and an API model (Apollo). These two are identical except for a 'start' field which is resolved from a string to an object. How to exclude the 'start' field from being inherited or somehow override it?
class Start {
iso: string;
local: string;
}
// database model
class BaseThing {
// a lot of other fields
start: string; // < - - I don't want to have 'any' type here
}
// API model
class Thing extends BaseThing {
// a lot of other fields [inherited]
start: Start; // < - - how to exclude start from being inherited or somehow override it?
}
This isn't really good practice: subclasses inherit superclass properties and methods. If inheritance isn't desired, it's possible one might really want composition instead of class hierarchies, but that's out of scope for this question. Let's show how to get the behavior you're looking for and then remind everyone at the end that it could lead to weird issues.
If you want to prevent the compiler from seeing the
BaseThing
constructor as constructing something with astart
property, you can use a type assertion to widen the type ofBaseThing
from (something like)new () => BaseThing
tonew () => Omit<BaseThing, "start">
using theOmit<T, K>
utility type:That's a bit ugly looking, but it works. The compiler sees
Thing
as inheriting everything exceptstart
fromBaseThing
.If you do this kind of thing often, you could think of refactoring this widening into a helper function like:
where
which can be hidden in a library somewhere.
PLEASE NOTE that, depending on the implementation of the base class, this sort of intentional widening and then incompatible re-narrowing could lead to trouble. Imagine something like this:
So far so good. But then:
This fails because the base class's
method()
depends onval
being astring
and not anything else. Pseudo-subclasses that changeval
to some non-string
type will be unhappy at runtime unless they also overridemethod()
. So anyone who does something like this which intentionally circumvents type safety warnings should take care not to trip over the part of the rug under which the problem has been swept.Playground link to code