diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa47b542e..b53f9af6bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Enhancements * Add support for using functions as default property values, in order to allow dynamic defaults [#5001](https://github.com/realm/realm-js/pull/5001), [#2393](https://github.com/realm/realm-js/issues/2393) +* All fields of a `Realm.Object` treated as optional by TypeScript when constructing a new class-based model, unless specified in the second type parameter [#5000](https://github.com/realm/realm-js/pull/5000) ### Fixed * ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?) diff --git a/types/index.d.ts b/types/index.d.ts index b7069fc7be..385a7d647d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -276,14 +276,36 @@ declare namespace Realm { type ObjectChangeCallback = (object: T, changes: ObjectChangeSet) => void; /** - * Object - * @see { @link https://realm.io/docs/javascript/latest/api/Realm.Object.html } + * Base class for a Realm Object. + * @see + * {@link https://realm.io/docs/javascript/latest/api/Realm.Object.html} + * + * @example + * To define a class `Person` which requires the `name` and `age` properties to be + * specified when it is being constructed, using the Realm Babel plugin to allow + * Typescript-only model definitions (otherwise it would require a `static` schema): + * ``` + * class Person extends Realm.Object { + * _id = new Realm.Types.ObjectId(); + * name: string; + * age: Realm.Types.Int; + * } + * ``` + * + * @typeParam `T` - The type of this class (e.g. if your class is `Person`, + * `T` should also be `Person` - this duplication is required due to how + * TypeScript works) + * + * @typeParam `RequiredProperties` - The names of any properties of this + * class which are required when an instance is constructed with `new`. Any + * properties not specified will be optional, and will default to a sensible + * null value if no default is specified elsewhere. */ - abstract class Object { + abstract class Object = never> { /** * Creates a new object in the database. */ - constructor(realm: Realm, values: Unmanaged); + constructor(realm: Realm, values: Unmanaged); /** * @returns An array of the names of the object's properties. @@ -1031,6 +1053,16 @@ type OmittedRealmTypes = Omit >; +/** Make all fields optional except those specified in K */ +type OptionalExcept = Partial & Pick; + +/** + * Omits all properties of a model which are not defined by the schema, + * making all properties optional except those specified in RequiredProperties. + */ +type OmittedRealmTypesWithRequired> = + OptionalExcept, RequiredProperties>; + /** Remaps realm types to "simpler" types (arrays and objects) */ type RemappedRealmTypes = RealmListsRemappedModelPart & @@ -1038,9 +1070,12 @@ type RemappedRealmTypes = /** * Joins T stripped of all keys which value extends Realm.Collection and all inherited from Realm.Object, - * with only the keys which value extends Realm.List, remapped as Arrays. + * with only the keys which value extends Realm.List, remapped as Arrays. All properties are optional + * except those specified in RequiredProperties. */ -type Unmanaged = OmittedRealmTypes & RemappedRealmTypes; +type Unmanaged = never> = + OmittedRealmTypesWithRequired & RemappedRealmTypes; + declare class Realm { static defaultPath: string;