Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: allow null for optional fields in TypeScript #13901

Merged
merged 4 commits into from Oct 4, 2023

Conversation

vkarpov15
Copy link
Collaborator

Summary

Apply #12748, #12781 to Mongoose 8. At runtime, Mongoose lets you store null for optional fields. TypeScript types should reflect this.

Examples

Copy link
Collaborator

@hasezoey hasezoey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have some questions, mainly is adding | null now required for ?: properties which should already have a | undefined added by ??

@@ -477,7 +477,7 @@ function gh12100() {
const TestModel = model('test', schema_with_string_id);
const obj = new TestModel();

expectType<string>(obj._id);
expectType<string | null>(obj._id);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is null here but not undefined?

test/types/queries.test.ts Show resolved Hide resolved
docs/migrating_to_8.md Outdated Show resolved Hide resolved
@vkarpov15
Copy link
Collaborator Author

@hasezoey "is adding | null now required for ?: properties which should already have a | undefined added by ??" <-- yes. ?: just adds | undefined, | null is separate.

@hasezoey
Copy link
Collaborator

?: just adds | undefined, | null is separate.

i know that they are separate and i know that the "more correct" way is |null|undefined, but those that do not want to deal with null and only undefined (at least in terms of types) is it still required to be added? like is there some kind of type incompatibility to not add |null?

Co-authored-by: hasezoey <hasezoey@gmail.com>
@vkarpov15
Copy link
Collaborator Author

@hasezoey I don't understand "those that do not want to deal with null and only undefined (at least in terms of types) is it still required to be added? like is there some kind of type incompatibility to not add |null?". Can you please clarify with some examples?

@hasezoey
Copy link
Collaborator

I don't understand "those that do not want to deal with null and only undefined (at least in terms of types) is it still required to be added? like is there some kind of type incompatibility to not add |null?". Can you please clarify with some examples?

i mean is the following still possible (/ supported) without type errors?

interface SomeSchema {
  prop1?: string;
  prop2?: number;
}
// instead of now
interface SomeSchema {
  prop1?: string | null;
  prop2?: number | null;
}

which would trickle down to something like typegoose

class SomeSchema {
  @prop()
  public prop1?: string;

  @prop()
  public prop2?: number;
}
// instead of
class SomeSchema {
  @prop()
  public prop1?: string | null;

  @prop()
  public prop2?: number | null;
}

personally even if the more correct way would be string | undefined | null, i would go with string | undefined (unless null is explicitly needed) because that makes type debugging (like hover) a lot more cleaner, especially because i have common functions like isNullOrUndefined (which is deprecated in utils nodejs) which would take care of both at runtime, but would only need to deal with undefined for the "undefined" case, where essentially undefined and null are treated the same

TL;DR: prop?: string is a lot more cleaner overall than prop?: string | null (or the "expanded type" prop: string | undefined | null) and i am asking if the "cleaner" way is still supported or will it give type-errors?

@vkarpov15
Copy link
Collaborator Author

@hasezoey you shouldn't need to change prop?: string to prop?: string | null in raw doc definitions. The following script compiles fine even with these changes.

import mongoose from 'mongoose';

interface IUser {
  prop?: string;
}

const schema = new mongoose.Schema<IUser>({ prop: String });
const TestModel = mongoose.model<IUser>('Test', schema);

const doc = new TestModel();
const foo: string | undefined | null = doc.prop;

Can you please try this PR out with Typegoose and see if anything breaks?

@hasezoey
Copy link
Collaborator

Can you please try this PR out with Typegoose and see if anything breaks?

seems to run fine (both runtime and types), though i will need to test it a little more in depth (against the 8.0 branch in general)

@vkarpov15 vkarpov15 added this to the 8.0 milestone Oct 4, 2023
@vkarpov15 vkarpov15 merged commit f7afc96 into 8.0 Oct 4, 2023
19 checks passed
@hasezoey hasezoey deleted the vkarpov15/gh-12748 branch October 5, 2023 10:20
@vkarpov15 vkarpov15 mentioned this pull request Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants