Skip to content

Commit

Permalink
feat(types): change "DocumentType" to actually use a proper "_id" type
Browse files Browse the repository at this point in the history
also slightly simplifys the type
  • Loading branch information
hasezoey committed Feb 19, 2023
1 parent 740507f commit c63c5f1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 10 deletions.
21 changes: 21 additions & 0 deletions docs/guides/faq.md
Expand Up @@ -70,3 +70,24 @@ class Cat {
_id: mongoose.Types.ObjectId;
}
```

### Why is `_id` `unknown`?

It is very likely that your class is just empty, and typescript somehow does not correctly match that and treats it like a generic object.

Example:

```ts
class Dummy {}
const DummyModel = getModelForClass(Dummy);
const newDoc = new DummyModel()
newDoc._id; // type: unknown

class Dummy {
// simple dummy property for types, will complain if actually used
public _dummy: never;
}
const DummyModel = getModelForClass(Dummy);
const newDoc = new DummyModel()
newDoc._id; // type: mongoose.Types.ObjectId
```
6 changes: 2 additions & 4 deletions src/types.ts
Expand Up @@ -11,10 +11,8 @@ import type { Severity, PropType } from './internal/constants';
* const doc: DocumentType<ClassName> = await NameModel.create({});
* ```
*/
export type DocumentType<T, QueryHelpers = BeAnObject> = (T extends { _id: unknown }
? mongoose.Document<T['_id'], QueryHelpers, T>
: mongoose.Document<any, QueryHelpers, T>) &
T &
export type DocumentType<T, QueryHelpers = BeAnObject> = mongoose.Document<unknown, QueryHelpers, T> &
mongoose.Require_id<T> &
IObjectWithTypegooseFunction;
/**
* Get the Type of an instance of a SubDocument with Class properties
Expand Down
17 changes: 11 additions & 6 deletions test/tests/types/basicTypegoose.test-d.ts
@@ -1,6 +1,6 @@
import { expectType, expectAssignable, expectError } from 'tsd-lite';
import * as typegoose from '../../../src/typegoose';
import { isDocument, isRefType } from '../../../src/typegoose';
import { isDocument, isRefType, prop } from '../../../src/typegoose';
import { BeAnObject, IObjectWithTypegooseFunction } from '../../../src/types';

// decorators return type
Expand All @@ -21,7 +21,10 @@ expectType<void>(typegoose.setGlobalOptions({}));
expectType<void>(typegoose.setLogLevel('DEBUG'));

// mongoose related function return types
class TestClass {}
class TestClass {
@prop()
public dummy?: string;
}

const TestClassModel = typegoose.getModelForClass(TestClass);

Expand Down Expand Up @@ -166,27 +169,29 @@ async function testDocumentType() {
const someNewDoc = new TestClassModel();

expectType<
typegoose.mongoose.Document<any, BeAnObject, TestClass> &
typegoose.mongoose.Document<unknown, BeAnObject, TestClass> &
TestClass &
IObjectWithTypegooseFunction & { _id: typegoose.mongoose.Types.ObjectId }
>(someNewDoc);

const someCreatedDoc = await TestClassModel.create();

expectType<
(typegoose.mongoose.Document<any, BeAnObject, TestClass> &
(typegoose.mongoose.Document<unknown, BeAnObject, TestClass> &
TestClass &
IObjectWithTypegooseFunction & { _id: typegoose.mongoose.Types.ObjectId })[]
>(someCreatedDoc);

const someFoundDoc = await TestClassModel.findOne();

expectType<
| (typegoose.mongoose.Document<any, BeAnObject, TestClass> &
| (typegoose.mongoose.Document<unknown, BeAnObject, TestClass> &
TestClass &
IObjectWithTypegooseFunction & { _id: typegoose.mongoose.Types.ObjectId })
| null
>(someFoundDoc);

expectType<typegoose.mongoose.Types.ObjectId>(someNewDoc._id);
}

testDocumentType();
Expand All @@ -205,7 +210,7 @@ async function gh732() {
const doc = await SomeClassModel.create({ someoptionalProp: 'helloopt', somerequiredProp: 'helloreq' });

expectType<
typegoose.mongoose.Document<any, BeAnObject, SomeClass> &
typegoose.mongoose.Document<unknown, BeAnObject, SomeClass> &
SomeClass &
IObjectWithTypegooseFunction & { _id: typegoose.mongoose.Types.ObjectId }
>(doc);
Expand Down

0 comments on commit c63c5f1

Please sign in to comment.