Q:

Reducing an interface in TypeScript

I have a mongoose model with an interface declaring it as such:
export interface IUserDocument extends mongoose.Document {
  surname: string;
  lastName: string;
}

export interface IUserModel extends mongoose.Model<IUserDocument> {
  myStaticMethodGoesHere(signature: string): void;
}

and the corresponding mongoose schema:
const UserSchema = new mongoose.Schema({
  surname: {type: String, required: true}, 
  lastname: {type: String, required: true},
})

Now I have to define how my User is structured 2 times already (mongoose schema AND typescript interface), which isn't DRY and is inconvenient. Unfortunately, if I want to use mongoose's lean method, I have to define  yet another interface:
export interface ILeanUserDocument {
  _id: mongoose.Types.ObjectId;
  __v: number;
  surname: string;
  lastName: string;
}

This is inconvenient and error prone. Is there a way for my lean interface to extend (I don't know the verb to use here) my IUserDocument interface but remove stuff from it?

A:

Extends is not the only way of adding properties to an interface. I believe you can work with type intersection to achieve what you're looking for. Note that in the example below all the names are just my guesses as to what would be appropriate, feel free to choose whatever you like.
You can define the interface
export interface IUserProperties {
  surname: string;
  lastName: string;
}

export type IUserDocument = mongoose.Document & IUserProperties;

and then later on
interface ILeanUserBase {
  _id: mongoose.Types.ObjectId;
  __v: number;
}

export type ILeanUserDocument = ILeanUserBase & IUserProperties;

Changes to IUserProperties will be reflected in both IUserModel and IUserDocument

