I've got an interface which extends 2 other interfaces.
The new interface is identical except for one thing: the field '_id' should be a string instead of an ObjectId (for easier server side operations).
Is it possible to overwrite the type of a field in the new interface? When I do it, tslint tells the new interface doesn't extend properly the previous ones.
Also I'd like to avoid union type such as: _id : ObjectId | string
export interface AchievementDb {
_id: ObjectID;
title: string;
description: string;
// more stuff
}
export interface AchievementUserProgress {
_id: ObjectID;
progress: number;
status: UserAchievementStatus;
// more stuff
}
export interface AchievementFull extends AchievementDb, AchievementUserProgress {
_id: string;
}
I would see two options:
interface WithID {
_id: ObjectID;
}
interface AchievementDbBase {
title: string;
description: string;
// more stuff
}
interface AchievementDb extends AchievementDbBase, WithID {
}
interface AchievementUserProgressBase {
progress: number;
// more stuff
}
interface AchievementUserProgress extends AchievementUserProgressBase, WithID {
}
interface AchievementFull extends AchievementDbBase, AchievementUserProgressBase {
_id: string;
}
Have a look at Exclude Types (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html) permitting this kind of mappings for types : http://ideasintosoftware.com/typescript-advanced-tricks/
in your case:
interface AchievementFull extends Omit<AchievementDb, '_id'>, Omit<AchievementUserProgress, '_id'> {
_id: string;
}
There are several options.
We could use a generic type parameter on the interfaces to specify the type of id
. We can specify a default type parameter to be able to keep using the interface without type parameters if necessary:
export interface AchievementDb<T = ObjectID> {
_id: T;
title: string;
description: string;
// more stuff
}
export interface AchievementUserProgress<T = ObjectID> {
_id: T;
progress: number;
status: UserAchievementStatus;
// more stuff
}
export interface AchievementFull extends AchievementDb<string>, AchievementUserProgress<string> {
}
Another option is to use Pick
and Exclude
to remove the field from the interfaces so we can override it as we wish (you will find a similar type defined as Omit
by others)
type ExcludeId<T> = Pick<T, Exclude<keyof T, '_id'>>
export interface AchievementFull extends ExcludeId<AchievementDb>, ExcludeId<AchievementUserProgress> {
_id: string;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With