Skip to content

Commit

Permalink
types: add VirtualsForModel helper to make it easier to set the corre…
Browse files Browse the repository at this point in the history
…ct type overrides for lean()

Re: Automattic/mongoose#12684
  • Loading branch information
vkarpov15 committed Jan 5, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 0c5c71b commit 436464f
Showing 6 changed files with 89 additions and 15 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -39,3 +39,21 @@ jobs:
mongod --version
echo `pwd`/mongodb-linux-x86_64-${{ matrix.mongo-os }}-${{ matrix.mongo }}/bin >> $GITHUB_PATH
- run: npm test

test-typescript:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
node: [22]
os: [ubuntu-22.04]
name: Node ${{ matrix.node }} MongoDB ${{ matrix.mongo }}
steps:
- uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3

- name: Setup node
uses: actions/setup-node@5b52f097d36d4b0b2f94ed6de710023fbb8b2236 # v3.1.0
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npm run test-typescript
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -58,3 +58,5 @@ typings/
.env

package-lock.json

test/test.js
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -25,3 +25,39 @@ userSchema.plugin(mongooseLeanVirtuals);
// won't be in `res`
const res = await UserModel.find().lean({ virtuals: true });
```

# TypeScript

Mongoose's `lean()` function typings don't know about `virtuals: true`, so you need to explicitly set the type when calling `lean()`.
This module exports a convenient `VirtualsForModel` helper type that returns the virtual property types for a given model.
The below example shows using `VirtualsForModel` along with `lean<TypeOverride>()`.

```ts
import mongooseLeanVirtuals, { VirtualsForModel } from "mongoose-lean-virtuals";

interface ITest {
name: string
}

const testSchema = new mongoose.Schema(
{ name: { type: String, required: true } },
{
virtuals: {
nameUpper: {
get() {
return this.name.toUpperCase();
}
}
}
}
);

testSchema.plugin(mongooseLeanVirtuals);

const TestModel = mongoose.model('Test', testSchema);

TestModel.findOne().lean<ITest & VirtualsForModel<typeof TestModel>>({ virtuals: true }).orFail().then(doc => {
const name: string = doc.name;
const nameUpper: string = doc.nameUpper;
});
```
4 changes: 3 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -3,5 +3,7 @@ declare module "mongoose-lean-virtuals" {
export default function mongooseLeanVirtuals(schema: mongoose.Schema<any, any, any, any>, opts?: any): void;
export function mongooseLeanVirtuals(schema: mongoose.Schema<any, any, any, any>, opts?: any): void;

export type VirtualsForModel<ModelType extends mongoose.Model<any, any, any, any>> = ModelType extends mongoose.Model<any, any, any, infer TVirtuals> ? TVirtuals : never;

export function parent(value: any): any;
}
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -8,7 +8,8 @@
"lint": "eslint .",
"test": "mocha ./test/*.js",
"test-integration": "mocha ./test/integration.js",
"test-travis": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/*"
"test-travis": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/*",
"test-typescript": "tsc --strict test/test.ts && rm ./test/test.js"
},
"repository": {
"type": "git",
@@ -24,14 +25,16 @@
"mpath": "^0.8.4"
},
"devDependencies": {
"@types/node": "22.10.5",
"acquit": "1.x",
"acquit-ignore": "0.1.0",
"acquit-markdown": "0.1.0",
"co": "4.6.0",
"eslint": "7.x",
"istanbul": "0.4.5",
"mocha": "5.2.x",
"mongoose": "8.x"
"mongoose": "8.x",
"typescript": "5.x"
},
"peerDependencies": {
"mongoose": ">=5.11.10"
37 changes: 25 additions & 12 deletions test/test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
/// <reference types="../index.d.ts" />

import * as mongoose from 'mongoose';
import * as mongooseLeanVirtuals from "mongoose-lean-virtuals";
import mongooseLeanVirtuals, { VirtualsForModel } from "mongoose-lean-virtuals";

interface Test {
name: string
interface ITest {
name: string
}
/*
const testSchema = new mongoose.Schema({
name: String
});
*/

const testSchema = new mongoose.Schema<Test>({
name: String
});
const testSchema = new mongoose.Schema(
{ name: { type: String, required: true } },
{
virtuals: {
nameUpper: {
get() {
return this.name.toUpperCase();
}
}
}
}
);

testSchema.plugin(mongooseLeanVirtuals.mongooseLeanVirtuals);
testSchema.plugin(mongooseLeanVirtuals);

const TestModel = mongoose.model('Test', testSchema);

TestModel.findOne().lean<ITest & VirtualsForModel<typeof TestModel>>({ virtuals: true }).orFail().then(doc => {
const name: string = doc.name;
const nameUpper: string = doc.nameUpper;
});

0 comments on commit 436464f

Please sign in to comment.