Derive TypeScript Types from Mongoose Schemas

When working with Mongoose and TypeScript, two helper types make your life much easier: /** * Extracts the “plain” shape of your schema— * just the fields you defined, without Mongoose’s built-in methods or `_id`. */ export type User = InferSchemaType; /** * Represents a fully “hydrated” Mongoose document: * your fields plus all of Mongoose’s methods and metadata * (e.g. `_id`, `save()`, `populate()`, etc.). */ export type UserDocument = HydratedDocument; export const userModel = model("user", userSchema); InferSchemaType • Produces a pure TypeScript type from your schema definition. • Use it whenever you need just the data shape (e.g. DTOs, service inputs/outputs). HydratedDocument • Wraps your base type T with Mongoose’s document helpers. • Use it for any function that deals with real, database-backed documents (e.g. returns from find, create, save). For example, in a repository interface you might write: export interface IUserRepository { findOneByEmail(email: string): Promise; findById(id: Types.ObjectId): Promise; create( createUserDto: Pick, ): Promise; } Here, each method clearly promises a “live” Mongoose document (with built-in methods) while elsewhere you can rely on User for pure data shapes—keeping your boundaries and types crystal clear. Let’s connect!!:

May 2, 2025 - 18:51
 0
Derive TypeScript Types from Mongoose Schemas

When working with Mongoose and TypeScript, two helper types make your life much easier:

/**
 * Extracts the “plain” shape of your schema—
 * just the fields you defined, without Mongoose’s built-in methods or `_id`.
 */
export type User = InferSchemaType<typeof userSchema>;

/**
 * Represents a fully “hydrated” Mongoose document:
 * your fields plus all of Mongoose’s methods and metadata
 * (e.g. `_id`, `save()`, `populate()`, etc.).
 */
export type UserDocument = HydratedDocument<User>;

export const userModel = model<UserDocument>("user", userSchema);

InferSchemaType

• Produces a pure TypeScript type from your schema definition.

• Use it whenever you need just the data shape (e.g. DTOs, service inputs/outputs).

HydratedDocument

• Wraps your base type T with Mongoose’s document helpers.

• Use it for any function that deals with real, database-backed
documents (e.g. returns from find, create, save).

For example, in a repository interface you might write:

export interface IUserRepository {
  findOneByEmail(email: string): Promise<UserDocument>;
  findById(id: Types.ObjectId): Promise<UserDocument>;
  create(
    createUserDto: Pick<CreateUserDto, 'email' | 'password'>,
  ): Promise<UserDocument>;
}

Here, each method clearly promises a “live” Mongoose document (with built-in methods) while elsewhere you can rely on User for pure data shapes—keeping your boundaries and types crystal clear.

Let’s connect!!: