diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4034be1c5..2a81f930f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Type Definition Check run: npm run ci:typecheck - name: Test Types - run: npm run test:types 2>&1 | tee silent.txt; + run: npm run test:types check-docs: name: Check Docs timeout-minutes: 10 diff --git a/eslint.config.test.mjs b/eslint.config.test.mjs index 8622d69d4..f2375e596 100644 --- a/eslint.config.test.mjs +++ b/eslint.config.test.mjs @@ -16,11 +16,7 @@ export default tseslint.config({ rules: { '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-unused-expressions': 'off', - '@typescript-eslint/no-empty-object-type': 'off', '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unsafe-return": "off", }, diff --git a/src/Cloud.ts b/src/Cloud.ts index 32678ddd0..c8fd781ad 100644 --- a/src/Cloud.ts +++ b/src/Cloud.ts @@ -37,7 +37,15 @@ import type { RequestOptions } from './RESTController'; * @returns {Promise} A promise that will be resolved with the result * of the function. */ -export function run(name: string, data: any, options: RequestOptions): Promise { +export function run any>( + name: string, + data?: null, + options?: RequestOptions +): Promise>; +export function run< + T extends (param: { [P in keyof Parameters[0]]: Parameters[0][P] }) => any, +>(name: string, data: Parameters[0], options?: RequestOptions): Promise>; +export function run(name: string, data?: any, options?: RequestOptions): Promise { if (typeof name !== 'string' || name.length === 0) { throw new TypeError('Cloud function name must be a string.'); } @@ -88,7 +96,7 @@ export function getJobStatus(jobStatusId: string): Promise { } const DefaultController = { - run(name: string, data: any, options: RequestOptions) { + run(name: string, data: any, options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); const payload = encode(data, true); @@ -105,12 +113,12 @@ const DefaultController = { }); }, - getJobsData(options: RequestOptions) { + getJobsData(options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'cloud_code/jobs/data', null, options); }, - async startJob(name: string, data: any, options: RequestOptions) { + async startJob(name: string, data: any, options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); const payload = encode(data, true); diff --git a/src/CoreManager.ts b/src/CoreManager.ts index c1a174248..02629c78c 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -19,10 +19,10 @@ type AnalyticsController = { track: (name: string, dimensions: { [key: string]: string }) => Promise; }; type CloudController = { - run: (name: string, data: any, options: RequestOptions) => Promise; - getJobsData: (options: RequestOptions) => Promise; + run: (name: string, data: any, options?: RequestOptions) => Promise; + getJobsData: (options?: RequestOptions) => Promise; /** Returns promise which resolves with JobStatusId of the job */ - startJob: (name: string, data: any, options: RequestOptions) => Promise; + startJob: (name: string, data: any, options?: RequestOptions) => Promise; }; type ConfigController = { current: () => Promise | ParseConfig; @@ -55,15 +55,15 @@ type ObjectController = { fetch: ( object: ParseObject | Array, forceFetch: boolean, - options: RequestOptions + options?: RequestOptions ) => Promise | ParseObject | undefined>; save: ( object: ParseObject | Array | null, - options: RequestOptions + options?: RequestOptions ) => Promise | ParseFile | undefined>; destroy: ( object: ParseObject | Array, - options: RequestOptions + options?: RequestOptions ) => Promise>; }; type ObjectStateController = { @@ -92,18 +92,52 @@ type QueryController = { find( className: string, params: QueryJSON, - options: RequestOptions + options?: RequestOptions ): Promise<{ results?: Array; className?: string; count?: number }>; aggregate( className: string, params: any, - options: RequestOptions + options?: RequestOptions ): Promise<{ results?: Array }>; }; -type EventuallyQueue = { - save: (object: ParseObject, serverOptions: SaveOptions) => Promise; - destroy: (object: ParseObject, serverOptions: RequestOptions) => Promise; - poll: (ms?: number) => void; +export type QueueObject = { + queueId: string; + action: string; + object: ParseObject; + serverOptions: SaveOptions | RequestOptions; + id: string; + className: string; + hash: string; + createdAt: Date; +}; +export type Queue = Array; +export type EventuallyQueue = { + save: (object: ParseObject, serverOptions?: SaveOptions) => Promise; + destroy: (object: ParseObject, serverOptions?: RequestOptions) => Promise; + generateQueueId: (action: string, object: ParseObject) => string; + enqueue( + action: string, + object: ParseObject, + serverOptions?: SaveOptions | RequestOptions + ): Promise; + store(data: Queue): Promise; + load(): Promise; + getQueue(): Promise; + setQueue(queue: Queue): Promise; + remove(queueId: string): Promise; + clear(): Promise; + queueItemExists(queue: Queue, queueId: string): number; + length(): Promise; + sendQueue(): Promise; + sendQueueCallback(object: ParseObject, queueObject: QueueObject): Promise; + poll(ms?: number): void; + stopPoll(): void; + isPolling(): boolean; + process: { + create(ObjectType: any, queueObject: any): Promise; + byId(ObjectType: any, queueObject: any): Promise; + byHash(ObjectType: any, queueObject: any): Promise; + }; }; type RESTController = { request: (method: string, path: string, data?: any, options?: RequestOptions) => Promise; @@ -122,10 +156,10 @@ type SchemaController = { delete: (className: string, options?: RequestOptions) => Promise; create: (className: string, params: any, options?: RequestOptions) => Promise; update: (className: string, params: any, options?: RequestOptions) => Promise; - send(className: string, method: string, params: any, options: RequestOptions): Promise; + send(className: string, method: string, params: any, options?: RequestOptions): Promise; }; type SessionController = { - getSession: (token: RequestOptions) => Promise; + getSession: (options?: RequestOptions) => Promise; }; type StorageController = | { @@ -165,24 +199,24 @@ type UserController = { setCurrentUser: (user: ParseUser) => Promise; currentUser: () => ParseUser | null; currentUserAsync: () => Promise; - signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise; - logIn: (user: ParseUser, options: RequestOptions) => Promise; + signUp: (user: ParseUser, attrs: AttributeMap, options?: RequestOptions) => Promise; + logIn: (user: ParseUser, options?: RequestOptions) => Promise; loginAs: (user: ParseUser, userId: string) => Promise; - become: (user: ParseUser, options: RequestOptions) => Promise; + become: (user: ParseUser, options?: RequestOptions) => Promise; hydrate: (user: ParseUser, userJSON: AttributeMap) => Promise; - logOut: (options: RequestOptions) => Promise; - me: (user: ParseUser, options: RequestOptions) => Promise; - requestPasswordReset: (email: string, options: RequestOptions) => Promise; + logOut: (options?: RequestOptions) => Promise; + me: (user: ParseUser, options?: RequestOptions) => Promise; + requestPasswordReset: (email: string, options?: RequestOptions) => Promise; updateUserOnDisk: (user: ParseUser) => Promise; - upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => Promise; + upgradeToRevocableSession: (user: ParseUser, options?: RequestOptions) => Promise; linkWith: (user: ParseUser, authData: AuthData, options?: FullOptions) => Promise; removeUserFromDisk: () => Promise; verifyPassword: ( username: string, password: string, - options: RequestOptions + options?: RequestOptions ) => Promise; - requestEmailVerification: (email: string, options: RequestOptions) => Promise; + requestEmailVerification: (email: string, options?: RequestOptions) => Promise; }; type HooksController = { get: (type: string, functionName?: string, triggerName?: string) => Promise; diff --git a/src/EventuallyQueue.ts b/src/EventuallyQueue.ts index a4cdb0ed8..2e3d0abfb 100644 --- a/src/EventuallyQueue.ts +++ b/src/EventuallyQueue.ts @@ -4,24 +4,12 @@ import ParseObject from './ParseObject'; import ParseQuery from './ParseQuery'; import Storage from './Storage'; +import type { Queue, QueueObject } from './CoreManager'; import type { SaveOptions } from './ParseObject'; import type { RequestOptions } from './RESTController'; -type QueueObject = { - queueId: string; - action: string; - object: ParseObject; - serverOptions: SaveOptions | RequestOptions; - id: string; - className: string; - hash: string; - createdAt: Date; -}; - -type Queue = Array; - const QUEUE_KEY = 'Parse/Eventually/Queue'; -let queueCache: QueueObject[] = []; +let queueCache: Queue = []; let dirtyCache = true; let polling: ReturnType | undefined = undefined; @@ -44,7 +32,7 @@ const EventuallyQueue = { * @static * @see Parse.Object#saveEventually */ - save(object: ParseObject, serverOptions: SaveOptions = {}): Promise { + save(object: ParseObject, serverOptions?: SaveOptions): Promise { return this.enqueue('save', object, serverOptions); }, @@ -59,7 +47,7 @@ const EventuallyQueue = { * @static * @see Parse.Object#destroyEventually */ - destroy(object: ParseObject, serverOptions: RequestOptions = {}): Promise { + destroy(object: ParseObject, serverOptions?: RequestOptions): Promise { return this.enqueue('destroy', object, serverOptions); }, @@ -92,7 +80,7 @@ const EventuallyQueue = { async enqueue( action: string, object: ParseObject, - serverOptions: SaveOptions | RequestOptions + serverOptions?: SaveOptions | RequestOptions ): Promise { const queueData = await this.getQueue(); const queueId = this.generateQueueId(action, object); @@ -112,7 +100,7 @@ const EventuallyQueue = { queueId, action, object: object.toJSON(), - serverOptions, + serverOptions: serverOptions || {}, id: object.id, className: object.className, hash: object.get('hash'), @@ -121,11 +109,11 @@ const EventuallyQueue = { return this.setQueue(queueData); }, - store(data: QueueObject[]) { + store(data: Queue): Promise { return Storage.setItemAsync(QUEUE_KEY, JSON.stringify(data)); }, - load() { + load(): Promise { return Storage.getItemAsync(QUEUE_KEY); }, @@ -134,10 +122,10 @@ const EventuallyQueue = { * * @function getQueue * @name Parse.EventuallyQueue.getQueue - * @returns {Promise} + * @returns {Promise} * @static */ - async getQueue(): Promise { + async getQueue(): Promise { if (dirtyCache) { queueCache = JSON.parse((await this.load()) || '[]'); dirtyCache = false; @@ -297,7 +285,7 @@ const EventuallyQueue = { * @param [ms] Milliseconds to ping the server. Default 2000ms * @static */ - poll(ms = 2000) { + poll(ms?: number): void { if (polling) { return; } @@ -311,7 +299,7 @@ const EventuallyQueue = { } }) .catch(e => e); - }, ms); + }, ms || 2000); }, /** @@ -321,7 +309,7 @@ const EventuallyQueue = { * @name Parse.EventuallyQueue.stopPoll * @static */ - stopPoll() { + stopPoll(): void { clearInterval(polling); polling = undefined; }, diff --git a/src/LiveQuerySubscription.ts b/src/LiveQuerySubscription.ts index c20232a30..79a59d822 100644 --- a/src/LiveQuerySubscription.ts +++ b/src/LiveQuerySubscription.ts @@ -1,6 +1,7 @@ import CoreManager from './CoreManager'; import { resolvingPromise } from './promiseUtils'; import type ParseQuery from './ParseQuery'; +import type { EventEmitter } from 'events'; /** * Creates a new LiveQuery Subscription. @@ -91,9 +92,9 @@ class LiveQuerySubscription { subscribePromise: any; unsubscribePromise: any; subscribed: boolean; - emitter: any; - on: any; - emit: any; + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; /* * @param {string | number} id - subscription id * @param {string} query - query to subscribe to @@ -106,8 +107,8 @@ class LiveQuerySubscription { this.subscribePromise = resolvingPromise(); this.unsubscribePromise = resolvingPromise(); this.subscribed = false; - const EventEmitter = CoreManager.getEventEmitter(); - this.emitter = new EventEmitter(); + const Emitter = CoreManager.getEventEmitter(); + this.emitter = new Emitter(); this.on = (eventName, listener) => this.emitter.on(eventName, listener); this.emit = (eventName, ...args) => this.emitter.emit(eventName, ...args); diff --git a/src/Parse.ts b/src/Parse.ts index 0041b3d1e..bd58958b8 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -1,7 +1,7 @@ import decode from './decode'; import encode from './encode'; import CryptoController from './CryptoController'; -import EventuallyQueue from './EventuallyQueue'; +import EQ from './EventuallyQueue'; import IndexedDBStorageController from './IndexedDBStorageController'; import InstallationController from './InstallationController'; import * as ParseOp from './ParseOp'; @@ -36,6 +36,7 @@ import LiveQueryClient from './LiveQueryClient'; import LocalDatastoreController from './LocalDatastoreController'; import StorageController from './StorageController'; import WebSocketController from './WebSocketController'; +import type { EventuallyQueue } from './CoreManager'; const Parse = { ACL, @@ -79,11 +80,11 @@ const Parse = { * @member {EventuallyQueue} Parse.EventuallyQueue * @static */ - set EventuallyQueue(queue: typeof EventuallyQueue) { + set EventuallyQueue(queue: EventuallyQueue) { CoreManager.setEventuallyQueue(queue); }, - get EventuallyQueue(): any { + get EventuallyQueue(): EventuallyQueue { return CoreManager.getEventuallyQueue(); }, @@ -117,7 +118,7 @@ const Parse = { CoreManager.setIfNeeded('EventEmitter', EventEmitter); CoreManager.setIfNeeded('LiveQuery', new ParseLiveQuery()); CoreManager.setIfNeeded('CryptoController', CryptoController); - CoreManager.setIfNeeded('EventuallyQueue', EventuallyQueue); + CoreManager.setIfNeeded('EventuallyQueue', EQ); CoreManager.setIfNeeded('InstallationController', InstallationController); CoreManager.setIfNeeded('LocalDatastoreController', LocalDatastoreController); CoreManager.setIfNeeded('StorageController', StorageController); @@ -342,7 +343,7 @@ const Parse = { * @static * @returns {boolean} */ - isLocalDatastoreEnabled() { + isLocalDatastoreEnabled(): boolean { return this.LocalDatastore.isEnabled; }, /** diff --git a/src/ParseConfig.ts b/src/ParseConfig.ts index 1689ead30..6bdd38807 100644 --- a/src/ParseConfig.ts +++ b/src/ParseConfig.ts @@ -77,7 +77,7 @@ class ParseConfig { * @returns {Promise} A promise that is resolved with a newly-created * configuration object when the get completes. */ - static get(options: RequestOptions = {}) { + static get(options?: RequestOptions) { const controller = CoreManager.getConfigController(); return controller.get(options); } @@ -166,7 +166,7 @@ const DefaultController = { }); }, - get(options: RequestOptions = {}) { + get(options?: RequestOptions) { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'config', {}, options).then(response => { diff --git a/src/ParseFile.ts b/src/ParseFile.ts index 681039d28..d53c8f947 100644 --- a/src/ParseFile.ts +++ b/src/ParseFile.ts @@ -68,8 +68,8 @@ class ParseFile { _previousSave?: Promise; _data?: string; _requestTask?: any; - _metadata?: object; - _tags?: object; + _metadata?: Record; + _tags?: Record; /** * @param name {String} The file's name. This will be prefixed by a unique @@ -205,7 +205,7 @@ class ParseFile { * * @returns {object} */ - metadata() { + metadata(): Record { return this._metadata; } @@ -214,7 +214,7 @@ class ParseFile { * * @returns {object} */ - tags() { + tags(): Record { return this._tags; } @@ -357,7 +357,7 @@ class ParseFile { * * @param {object} metadata Key value pairs to be stored with file object */ - setMetadata(metadata: any) { + setMetadata(metadata: Record) { if (metadata && typeof metadata === 'object') { Object.keys(metadata).forEach(key => { this.addMetadata(key, metadata[key]); @@ -382,7 +382,7 @@ class ParseFile { * * @param {object} tags Key value pairs to be stored with file object */ - setTags(tags: any) { + setTags(tags: Record) { if (tags && typeof tags === 'object') { Object.keys(tags).forEach(key => { this.addTag(key, tags[key]); diff --git a/src/ParseGeoPoint.ts b/src/ParseGeoPoint.ts index 2b18b991a..230384473 100644 --- a/src/ParseGeoPoint.ts +++ b/src/ParseGeoPoint.ts @@ -31,7 +31,7 @@ class ParseGeoPoint { * @param {number} arg2 The longitude of the GeoPoint */ constructor( - arg1?: Array | { latitude: number; longitude: number } | number, + arg1?: [number, number] | { latitude: number; longitude: number } | number, arg2?: number ) { if (Array.isArray(arg1)) { diff --git a/src/ParseInstallation.ts b/src/ParseInstallation.ts index ef87e95f7..9d90ae18a 100644 --- a/src/ParseInstallation.ts +++ b/src/ParseInstallation.ts @@ -1,6 +1,7 @@ import CoreManager from './CoreManager'; import ParseError from './ParseError'; import ParseObject, { Attributes } from './ParseObject'; +import type { AttributeKey } from './ParseObject'; type DeviceInterface = { IOS: string; @@ -39,7 +40,7 @@ class ParseInstallation extends ParseObject extends ParseObject); } /** @@ -65,7 +66,7 @@ class ParseInstallation extends ParseObject); } /** @@ -76,7 +77,7 @@ class ParseInstallation extends ParseObject); } /** @@ -89,7 +90,7 @@ class ParseInstallation extends ParseObject); } /** @@ -100,7 +101,7 @@ class ParseInstallation extends ParseObject); } /** @@ -111,7 +112,7 @@ class ParseInstallation extends ParseObject); } /** @@ -122,7 +123,7 @@ class ParseInstallation extends ParseObject); } /** @@ -133,7 +134,7 @@ class ParseInstallation extends ParseObject); } /** @@ -144,7 +145,7 @@ class ParseInstallation extends ParseObject); } /** @@ -155,7 +156,7 @@ class ParseInstallation extends ParseObject); } /** @@ -166,7 +167,7 @@ class ParseInstallation extends ParseObject); } /** @@ -177,7 +178,7 @@ class ParseInstallation extends ParseObject); } /** @@ -188,7 +189,7 @@ class ParseInstallation extends ParseObject); } /** @@ -232,7 +233,7 @@ class ParseInstallation extends ParseObject extends ParseObject, value); } } diff --git a/src/ParseLiveQuery.ts b/src/ParseLiveQuery.ts index 8c7e8188f..769e2cf1d 100644 --- a/src/ParseLiveQuery.ts +++ b/src/ParseLiveQuery.ts @@ -1,5 +1,6 @@ import LiveQueryClient from './LiveQueryClient'; import CoreManager from './CoreManager'; +import type { EventEmitter } from 'events'; function getLiveQueryClient(): Promise { return CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); @@ -33,13 +34,13 @@ function getLiveQueryClient(): Promise { * @static */ class LiveQuery { - emitter: any; - on: any; - emit: any; + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; constructor() { - const EventEmitter = CoreManager.getEventEmitter(); - this.emitter = new EventEmitter(); + const Emitter = CoreManager.getEventEmitter(); + this.emitter = new Emitter(); this.on = (eventName: string, listener: any) => this.emitter.on(eventName, listener); this.emit = (eventName: string, ...args: any) => this.emitter.emit(eventName, ...args); // adding listener so process does not crash diff --git a/src/ParseObject.ts b/src/ParseObject.ts index d0ab2932c..27a602988 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -60,9 +60,12 @@ type FetchOptions = { }; export type SetOptions = { - ignoreValidation: boolean; + ignoreValidation?: boolean; + unset?: boolean; }; +export type AttributeKey = Extract; + export interface Attributes { [key: string]: any; } @@ -73,6 +76,14 @@ interface JSONBaseAttributes { updatedAt: string; } +interface CommonAttributes { + ACL: ParseACL; +} + +type AtomicKey = { + [K in keyof T]: NonNullable extends any[] ? K : never; +}; + type Encode = T extends ParseObject ? ReturnType | Pointer : T extends ParseACL | ParseGeoPoint | ParsePolygon | ParseRelation | ParseFile @@ -143,7 +154,7 @@ class ParseObject { */ constructor( className?: string | { className: string; [attr: string]: any }, - attributes?: T | Attributes, + attributes?: T, options?: SetOptions ) { // Enable legacy initializers @@ -572,8 +583,8 @@ class ParseObject { * @param {object} other - An other object ot compare * @returns {boolean} */ - equals(other: any): boolean { - if (this === other) { + equals(other: T): boolean { + if ((this as any) === (other as any)) { return true; } return ( @@ -592,7 +603,7 @@ class ParseObject { * @param {string} attr An attribute name (optional). * @returns {boolean} */ - dirty(attr?: string): boolean { + dirty>(attr?: K): boolean { if (!this.id) { return true; } @@ -623,7 +634,7 @@ class ParseObject { * * @returns {string[]} */ - dirtyKeys(): Array { + dirtyKeys(): string[] { const pendingOps = this._getPendingOps(); const keys = {}; for (let i = 0; i < pendingOps.length; i++) { @@ -686,7 +697,7 @@ class ParseObject { * @param {string} attr The string name of an attribute. * @returns {*} */ - get(attr: string): any { + get>(attr: K): T[K] { return this.attributes[attr]; } @@ -696,7 +707,7 @@ class ParseObject { * @param {string} attr The attribute to get the relation for. * @returns {Parse.Relation} */ - relation = Extract>( + relation = AttributeKey>( attr: T[K] extends ParseRelation ? K : never ): ParseRelation { const value = this.get(attr) as any; @@ -716,7 +727,7 @@ class ParseObject { * @param {string} attr The string name of an attribute. * @returns {string} */ - escape(attr: string): string { + escape>(attr: K): string { let val = this.attributes[attr]; if (val == null) { return ''; @@ -737,7 +748,7 @@ class ParseObject { * @param {string} attr The string name of the attribute. * @returns {boolean} */ - has(attr: string): boolean { + has>(attr: K): boolean { const attributes = this.attributes; if (Object.hasOwn(attributes, attr)) { return attributes[attr] != null; @@ -775,8 +786,12 @@ class ParseObject { * The only supported option is error. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - set(key: any, value?: any, options?: any): this { - let changes = {}; + set>( + key: K | (Pick | T), + value?: SetOptions | (T[K] extends undefined ? never : T[K]), + options?: SetOptions + ): this { + let changes: any = {}; const newOps = {}; if (key && typeof key === 'object') { changes = key; @@ -786,7 +801,6 @@ class ParseObject { } else { return this; } - options = options || {}; let readonly = []; if (typeof (this.constructor as any).readOnlyAttributes === 'function') { @@ -870,7 +884,7 @@ class ParseObject { * @param options * @returns {Parse.Object} Returns the object, so you can chain this call. */ - unset(attr: string, options?: { [opt: string]: any }): this { + unset>(attr: K, options?: SetOptions): this { options = options || {}; options.unset = true; return this.set(attr, null, options); @@ -884,14 +898,14 @@ class ParseObject { * @param amount {Number} The amount to increment by (optional). * @returns {Parse.Object} Returns the object, so you can chain this call. */ - increment(attr: string, amount?: number): this { + increment>(attr: K, amount?: number): this { if (typeof amount === 'undefined') { amount = 1; } if (typeof amount !== 'number') { throw new Error('Cannot increment by a non-numeric amount.'); } - return this.set(attr, new IncrementOp(amount)); + return this.set(attr, new IncrementOp(amount) as any); } /** @@ -902,14 +916,14 @@ class ParseObject { * @param amount {Number} The amount to decrement by (optional). * @returns {Parse.Object} Returns the object, so you can chain this call. */ - decrement(attr: string, amount?: number): this { + decrement>(attr: K, amount?: number): this { if (typeof amount === 'undefined') { amount = 1; } if (typeof amount !== 'number') { throw new Error('Cannot decrement by a non-numeric amount.'); } - return this.set(attr, new IncrementOp(amount * -1)); + return this.set(attr, new IncrementOp(amount * -1) as any); } /** @@ -920,8 +934,8 @@ class ParseObject { * @param item {} The item to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - add(attr: string, item: any): this { - return this.set(attr, new AddOp([item])); + add[keyof T]>(attr: K, item: NonNullable[number]): this { + return this.set(attr as any, new AddOp([item]) as any); } /** @@ -932,8 +946,8 @@ class ParseObject { * @param items {Object[]} The items to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addAll(attr: string, items: Array): this { - return this.set(attr, new AddOp(items)); + addAll[keyof T]>(attr: K, items: NonNullable): this { + return this.set(attr as any, new AddOp(items) as any); } /** @@ -945,8 +959,8 @@ class ParseObject { * @param item {} The object to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addUnique(attr: string, item: any): this { - return this.set(attr, new AddUniqueOp([item])); + addUnique[keyof T]>(attr: K, item: NonNullable[number]): this { + return this.set(attr as any, new AddUniqueOp([item]) as any); } /** @@ -958,8 +972,8 @@ class ParseObject { * @param items {Object[]} The objects to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addAllUnique(attr: string, items: Array): this { - return this.set(attr, new AddUniqueOp(items)); + addAllUnique[keyof T]>(attr: K, items: NonNullable): this { + return this.set(attr as any, new AddUniqueOp(items) as any); } /** @@ -970,8 +984,8 @@ class ParseObject { * @param item {} The object to remove. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - remove(attr: string, item: any): this { - return this.set(attr, new RemoveOp([item])); + remove[keyof T]>(attr: K, item: NonNullable[number]): this { + return this.set(attr as any, new RemoveOp([item]) as any); } /** @@ -982,8 +996,8 @@ class ParseObject { * @param items {Object[]} The object to remove. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - removeAll(attr: string, items: Array): this { - return this.set(attr, new RemoveOp(items)); + removeAll[keyof T]>(attr: K, items: NonNullable): this { + return this.set(attr as any, new RemoveOp(items) as any); } /** @@ -995,7 +1009,7 @@ class ParseObject { * @param attr {String} The key. * @returns {Parse.Op | undefined} The operation, or undefined if none. */ - op(attr: string): Op | undefined { + op>(attr: K): Op | undefined { const pending = this._getPendingOps(); for (let i = pending.length; i--;) { if (pending[i][attr]) { @@ -1027,7 +1041,7 @@ class ParseObject { attributes = copy; } if (clone.set) { - clone.set(attributes); + clone.set(attributes as any); } return clone; } @@ -1149,7 +1163,7 @@ class ParseObject { * @see Parse.Object#get */ getACL(): ParseACL | null { - const acl = this.get('ACL'); + const acl: any = this.get('ACL' as AttributeKey); if (acl instanceof ParseACL) { return acl; } @@ -1165,7 +1179,7 @@ class ParseObject { * @see Parse.Object#set */ setACL(acl: ParseACL, options?: any): this { - return this.set('ACL', acl, options); + return this.set('ACL' as AttributeKey, acl as any, options); } /** @@ -1173,7 +1187,7 @@ class ParseObject { * * @param {string} [keys] - specify which fields to revert */ - revert(...keys: Array): void { + revert(...keys: Array>): void { let keysToRevert; if (keys.length) { keysToRevert = []; @@ -1205,7 +1219,7 @@ class ParseObject { erasable[attr] = true; } } - return this.set(erasable, { unset: true }); + return this.set(erasable as any, { unset: true }); } /** @@ -1282,7 +1296,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - async saveEventually(options: SaveOptions): Promise { + async saveEventually(options?: SaveOptions): Promise { try { await this.save(null, options); } catch (e) { @@ -1357,9 +1371,13 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - async save( - arg1?: undefined | string | { [attr: string]: any } | null, - arg2?: SaveOptions | any, + async save>( + arg1?: Pick | T | null, + arg2?: SaveOptions + ): Promise; + async save>( + arg1: K, + arg2: T[K] extends undefined ? never : T[K], arg3?: SaveOptions ): Promise { let attrs; @@ -1429,7 +1447,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - async destroyEventually(options: RequestOptions): Promise { + async destroyEventually(options?: RequestOptions): Promise { try { await this.destroy(options); } catch (e) { @@ -1455,7 +1473,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - destroy(options: RequestOptions): Promise { + destroy(options?: RequestOptions): Promise { if (!this.id) { return Promise.resolve(); } @@ -1647,7 +1665,7 @@ class ParseObject { */ static fetchAllWithInclude( list: T[], - keys: string | Array>, + keys: keyof T['attributes'] | Array, options?: RequestOptions ): Promise { options = options || {}; @@ -1687,7 +1705,7 @@ class ParseObject { */ static fetchAllIfNeededWithInclude( list: T[], - keys: string | Array>, + keys: keyof T['attributes'] | Array, options?: RequestOptions ): Promise { options = options || {}; @@ -1798,7 +1816,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroyAll * completes. */ - static destroyAll(list: Array, options: SaveOptions = {}) { + static destroyAll(list: Array, options?: SaveOptions) { const destroyOptions = ParseObject._getRequestOptions(options); return CoreManager.getObjectController().destroy(list, destroyOptions); } @@ -1867,7 +1885,7 @@ class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference */ - static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject { + static fromJSON(json: any, override?: boolean, dirty?: boolean): T { if (!json.className) { throw new Error('Cannot create an object without a className'); } @@ -2241,7 +2259,7 @@ const DefaultController = { fetch( target: ParseObject | Array, forceFetch: boolean, - options: RequestOptions + options?: RequestOptions ): Promise | ParseObject | undefined> { const localDatastore = CoreManager.getLocalDatastore(); if (Array.isArray(target)) { @@ -2345,7 +2363,7 @@ const DefaultController = { async destroy( target: ParseObject | Array, - options: RequestOptions + options?: RequestOptions ): Promise> { if (options && options.batchSize && options.transaction) throw new ParseError( @@ -2432,7 +2450,7 @@ const DefaultController = { save( target: ParseObject | null | Array, - options: RequestOptions + options?: RequestOptions ): Promise | ParseFile | undefined> { if (options && options.batchSize && options.transaction) return Promise.reject( diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index 913e8b471..85eacae7b 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -9,6 +9,7 @@ import { DEFAULT_PIN } from './LocalDatastoreUtils'; import type LiveQuerySubscription from './LiveQuerySubscription'; import type { RequestOptions, FullOptions } from './RESTController'; +import type { Pointer } from './ParseObject'; type BatchOptions = FullOptions & { batchSize?: number; @@ -54,6 +55,12 @@ export type QueryJSON = { comment?: string; }; +interface BaseAttributes { + createdAt: Date; + objectId: string; + updatedAt: Date; +} + /** * Converts a string into a regex that matches it. * Surrounding with \Q .. \E does this, we just need to escape any \E's in @@ -357,7 +364,11 @@ class ParseQuery { * @param value * @returns {Parse.Query} */ - _addCondition(key: string, condition: string, value: any): this { + _addCondition( + key: K, + condition: string, + value: any + ): this { if (!this._where[key] || typeof this._where[key] === 'string') { this._where[key] = {}; } @@ -637,7 +648,7 @@ class ParseQuery { * the query completes. */ get(objectId: string, options?: QueryOptions): Promise { - this.equalTo('objectId', objectId); + this.equalTo('objectId', objectId as any); const firstOptions = ParseObject._getRequestOptions(options); return this.first(firstOptions).then(response => { @@ -774,7 +785,10 @@ class ParseQuery { * @param {string} [options.sessionToken] A valid session token, used for making a request on behalf of a specific user. * @returns {Promise} A promise that is resolved with the query completes. */ - distinct(key: string, options?: { sessionToken?: string }): Promise> { + distinct( + key: K, + options?: { sessionToken?: string } + ): Promise { options = options || {}; const distinctOptions: { sessionToken?: string; useMasterKey: boolean } = { useMasterKey: true, @@ -1158,15 +1172,23 @@ class ParseQuery { * @param value The value that the Parse.Object must contain. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - equalTo(key: string | { [key: string]: any }, value?: any): this { + equalTo( + key: K, + value: + | T['attributes'][K] + | (T['attributes'][K] extends ParseObject + ? Pointer + : T['attributes'][K] extends Array + ? E + : never) + ): this { if (key && typeof key === 'object') { - Object.entries(key).forEach(([k, val]) => this.equalTo(k, val)); + Object.entries(key).forEach(([k, val]) => this.equalTo(k, val as any)); return this; } if (typeof value === 'undefined') { return this.doesNotExist(key as string); } - this._where[key as string] = encode(value, false, true); return this; } @@ -1179,12 +1201,21 @@ class ParseQuery { * @param value The value that must not be equalled. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notEqualTo(key: string | { [key: string]: any }, value?: any): this { + notEqualTo( + key: K, + value: + | T['attributes'][K] + | (T['attributes'][K] extends ParseObject + ? Pointer + : T['attributes'][K] extends Array + ? E + : never) + ): this { if (key && typeof key === 'object') { - Object.entries(key).forEach(([k, val]) => this.notEqualTo(k, val)); + Object.entries(key).forEach(([k, val]) => this.notEqualTo(k, val as any)); return this; } - return this._addCondition(key as string, '$ne', value); + return this._addCondition(key, '$ne', value); } /** @@ -1195,7 +1226,10 @@ class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThan(key: string, value: any): this { + lessThan( + key: K, + value: T['attributes'][K] + ): this { return this._addCondition(key, '$lt', value); } @@ -1207,7 +1241,10 @@ class ParseQuery { * @param value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThan(key: string, value: any): this { + greaterThan( + key: K, + value: T['attributes'][K] + ): this { return this._addCondition(key, '$gt', value); } @@ -1219,7 +1256,10 @@ class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThanOrEqualTo(key: string, value: any): this { + lessThanOrEqualTo( + key: K, + value: T['attributes'][K] + ): this { return this._addCondition(key, '$lte', value); } @@ -1231,7 +1271,10 @@ class ParseQuery { * @param {*} value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThanOrEqualTo(key: string, value: any): this { + greaterThanOrEqualTo( + key: K, + value: T['attributes'][K] + ): this { return this._addCondition(key, '$gte', value); } @@ -1240,11 +1283,14 @@ class ParseQuery { * be contained in the provided list of values. * * @param {string} key The key to check. - * @param {Array<*>} value The values that will match. + * @param {Array<*>} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedIn(key: string, value: Array): this { - return this._addCondition(key, '$in', value); + containedIn( + key: K, + values: Array + ): this { + return this._addCondition(key, '$in', values); } /** @@ -1252,11 +1298,14 @@ class ParseQuery { * not be contained in the provided list of values. * * @param {string} key The key to check. - * @param {Array<*>} value The values that will not match. + * @param {Array<*>} values The values that will not match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notContainedIn(key: string, value: Array): this { - return this._addCondition(key, '$nin', value); + notContainedIn( + key: K, + values: Array + ): this { + return this._addCondition(key, '$nin', values); } /** @@ -1267,7 +1316,10 @@ class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedBy(key: string, values: Array): this { + containedBy( + key: K, + values: Array + ): this { return this._addCondition(key, '$containedBy', values); } @@ -1279,7 +1331,7 @@ class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containsAll(key: string, values: Array): this { + containsAll(key: K, values: any[]): this { return this._addCondition(key, '$all', values); } @@ -1291,7 +1343,10 @@ class ParseQuery { * @param {Array} values The string values that will match as starting string. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containsAllStartingWith(key: string, values: Array): this { + containsAllStartingWith( + key: K, + values: any[] + ): this { if (!Array.isArray(values)) { values = [values]; } @@ -1309,7 +1364,7 @@ class ParseQuery { * @param {string} key The key that should exist. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - exists(key: string): this { + exists(key: K): this { return this._addCondition(key, '$exists', true); } @@ -1319,7 +1374,7 @@ class ParseQuery { * @param {string} key The key that should not exist * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotExist(key: string): this { + doesNotExist(key: K): this { return this._addCondition(key, '$exists', false); } @@ -1333,7 +1388,11 @@ class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matches(key: string, regex: RegExp | string, modifiers?: string): this { + matches( + key: K, + regex: RegExp | string, + modifiers?: string + ): this { this._addCondition(key, '$regex', regex); if (!modifiers) { modifiers = ''; @@ -1361,7 +1420,10 @@ class ParseQuery { * @param {Parse.Query} query The query that should match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matchesQuery(key: string, query: ParseQuery): this { + matchesQuery( + key: K, + query: ParseQuery + ): this { const queryJSON = query.toJSON(); queryJSON.className = query.className; return this._addCondition(key, '$inQuery', queryJSON); @@ -1376,7 +1438,10 @@ class ParseQuery { * @param {Parse.Query} query The query that should not match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotMatchQuery(key: string, query: ParseQuery): this { + doesNotMatchQuery( + key: K, + query: ParseQuery + ): this { const queryJSON = query.toJSON(); queryJSON.className = query.className; return this._addCondition(key, '$notInQuery', queryJSON); @@ -1393,7 +1458,11 @@ class ParseQuery { * @param {Parse.Query} query The query to run. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matchesKeyInQuery(key: string, queryKey: string, query: ParseQuery): this { + matchesKeyInQuery< + U extends ParseObject, + K extends keyof T['attributes'], + X extends Extract, + >(key: K, queryKey: X, query: ParseQuery): this { const queryJSON = query.toJSON(); queryJSON.className = query.className; return this._addCondition(key, '$select', { @@ -1413,7 +1482,11 @@ class ParseQuery { * @param {Parse.Query} query The query to run. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotMatchKeyInQuery(key: string, queryKey: string, query: ParseQuery): this { + doesNotMatchKeyInQuery< + U extends ParseObject, + K extends keyof T['attributes'] | keyof BaseAttributes, + X extends Extract, + >(key: K, queryKey: X, query: ParseQuery): this { const queryJSON = query.toJSON(); queryJSON.className = query.className; return this._addCondition(key, '$dontSelect', { @@ -1430,7 +1503,10 @@ class ParseQuery { * @param {string} substring The substring that the value must contain. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - contains(key: string, substring: string): this { + contains( + key: K, + substring: string + ): this { if (typeof substring !== 'string') { throw new Error('The value being searched for must be a string.'); } @@ -1466,7 +1542,11 @@ class ParseQuery { * @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - fullText(key: string, value: string, options: FullTextQueryOptions = {}): this { + fullText( + key: K, + value: string, + options?: FullTextQueryOptions + ): this { options = options || {}; if (!key) { @@ -1513,7 +1593,7 @@ class ParseQuery { */ sortByTextScore() { this.ascending('$score'); - this.select(['$score']); + this.select(['$score'] as any); return this; } @@ -1527,7 +1607,11 @@ class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - startsWith(key: string, prefix: string, modifiers?: string): this { + startsWith( + key: K, + prefix: string, + modifiers?: string + ): this { if (typeof prefix !== 'string') { throw new Error('The value being searched for must be a string.'); } @@ -1543,7 +1627,11 @@ class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - endsWith(key: string, suffix: string, modifiers?: string): this { + endsWith( + key: K, + suffix: string, + modifiers?: string + ): this { if (typeof suffix !== 'string') { throw new Error('The value being searched for must be a string.'); } @@ -1558,7 +1646,7 @@ class ParseQuery { * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - near(key: string, point: ParseGeoPoint): this { + near(key: K, point: ParseGeoPoint): this { if (!(point instanceof ParseGeoPoint)) { // Try to cast it as a GeoPoint point = new ParseGeoPoint(point); @@ -1578,7 +1666,12 @@ class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinRadians(key: string, point: ParseGeoPoint, maxDistance: number, sorted?: boolean): this { + withinRadians( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this { if (sorted || sorted === undefined) { this.near(key, point); return this._addCondition(key, '$maxDistance', maxDistance); @@ -1602,7 +1695,12 @@ class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinMiles(key: string, point: ParseGeoPoint, maxDistance: number, sorted: boolean): this { + withinMiles( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this { return this.withinRadians(key, point, maxDistance / 3958.8, sorted); } @@ -1619,7 +1717,12 @@ class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinKilometers(key: string, point: ParseGeoPoint, maxDistance: number, sorted: boolean): this { + withinKilometers( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this { return this.withinRadians(key, point, maxDistance / 6371.0, sorted); } @@ -1635,7 +1738,11 @@ class ParseQuery { * The upper-right inclusive corner of the box. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinGeoBox(key: string, southwest: ParseGeoPoint, northeast: ParseGeoPoint): this { + withinGeoBox( + key: K, + southwest: ParseGeoPoint, + northeast: ParseGeoPoint + ): this { if (!(southwest instanceof ParseGeoPoint)) { southwest = new ParseGeoPoint(southwest); } @@ -1657,7 +1764,10 @@ class ParseQuery { * @param {Array} points Array of Coordinates / GeoPoints * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinPolygon(key: string, points: Array>): this { + withinPolygon( + key: K, + points: number[][] + ): this { return this._addCondition(key, '$geoWithin', { $polygon: points }); } @@ -1669,7 +1779,10 @@ class ParseQuery { * @param {Parse.GeoPoint} point * @returns {Parse.Query} Returns the query, so you can chain this call. */ - polygonContains(key: string, point: ParseGeoPoint): this { + polygonContains( + key: K, + point: ParseGeoPoint + ): this { return this._addCondition(key, '$geoIntersects', { $point: point }); } @@ -1699,7 +1812,7 @@ class ParseQuery { if (!this._order) { this._order = []; } - keys.forEach(key => { + keys.forEach((key: any) => { if (Array.isArray(key)) { key = key.join(); } @@ -1733,7 +1846,7 @@ class ParseQuery { if (!this._order) { this._order = []; } - keys.forEach(key => { + keys.forEach((key: any) => { if (Array.isArray(key)) { key = key.join(); } @@ -1741,7 +1854,7 @@ class ParseQuery { key .replace(/\s/g, '') .split(',') - .map(k => { + .map((k: string) => { return '-' + k; }) ); @@ -1809,12 +1922,14 @@ class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to include. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - include(...keys: Array>): this { + include( + ...keys: Array> + ): this { keys.forEach(key => { if (Array.isArray(key)) { - this._include = this._include.concat(key); + this._include = this._include.concat(key as string[]); } else { - this._include.push(key); + this._include.push(key as string); } }); return this; @@ -1839,15 +1954,17 @@ class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to include. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - select(...keys: Array>): this { + select( + ...keys: Array> + ): this { if (!this._select) { this._select = []; } keys.forEach(key => { if (Array.isArray(key)) { - this._select = this._select.concat(key); + this._select = this._select.concat(key as string[]); } else { - this._select.push(key); + this._select.push(key as string); } }); return this; @@ -1862,12 +1979,14 @@ class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to exclude. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - exclude(...keys: Array>): this { + exclude( + ...keys: Array> + ): this { keys.forEach(key => { if (Array.isArray(key)) { - this._exclude = this._exclude.concat(key); + this._exclude = this._exclude.concat(key as string[]); } else { - this._exclude.push(key); + this._exclude.push(key as string); } }); return this; @@ -1881,12 +2000,14 @@ class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to watch. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - watch(...keys: Array>): this { + watch( + ...keys: Array> + ): this { keys.forEach(key => { if (Array.isArray(key)) { - this._watch = this._watch.concat(key); + this._watch = this._watch.concat(key as string[]); } else { - this._watch.push(key); + this._watch.push(key as string); } }); return this; @@ -2082,7 +2203,7 @@ const DefaultController = { find( className: string, params: QueryJSON, - options: RequestOptions + options?: RequestOptions ): Promise<{ results: Array }> { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'classes/' + className, params, options); @@ -2091,7 +2212,7 @@ const DefaultController = { aggregate( className: string, params: any, - options: RequestOptions + options?: RequestOptions ): Promise<{ results: Array }> { const RESTController = CoreManager.getRESTController(); diff --git a/src/ParseRole.ts b/src/ParseRole.ts index 50262c37d..7bcee4525 100644 --- a/src/ParseRole.ts +++ b/src/ParseRole.ts @@ -3,6 +3,7 @@ import ParseACL from './ParseACL'; import ParseError from './ParseError'; import ParseObject, { Attributes, SetOptions } from './ParseObject'; +import type { AttributeKey } from './ParseObject'; import type { AttributeMap } from './ObjectStateMutations'; import type ParseRelation from './ParseRelation'; import type ParseUser from './ParseUser'; @@ -41,7 +42,7 @@ class ParseRole extends ParseObject { * @returns {string} the name of the role. */ getName(): string | null { - const name = this.get('name'); + const name = this.get('name' as AttributeKey); if (name == null || typeof name === 'string') { return name; } @@ -67,7 +68,7 @@ class ParseRole extends ParseObject { */ setName(name: string, options?: SetOptions): this { this._validateName(name); - return this.set('name', name, options); + return this.set('name' as AttributeKey, name as any, options); } /** diff --git a/src/ParseSchema.ts b/src/ParseSchema.ts index 8daab6076..8e849463d 100644 --- a/src/ParseSchema.ts +++ b/src/ParseSchema.ts @@ -1,8 +1,59 @@ import CoreManager from './CoreManager'; import ParseObject from './ParseObject'; import ParseCLP from './ParseCLP'; - +import type ParseGeoPoint from './ParseGeoPoint'; +import type ParseFile from './ParseFile'; +import type ParsePolygon from './ParsePolygon'; +import type ParseRelation from './ParseRelation'; import type { PermissionsMap } from './ParseCLP'; +import type { Pointer } from './ParseObject'; + +type Bytes = string; + +type TYPE = + | 'String' + | 'Number' + | 'Bytes' + | 'Boolean' + | 'Date' + | 'File' + | 'GeoPoint' + | 'Polygon' + | 'Array' + | 'Object' + | 'Pointer' + | 'Relation'; + +type AttrType = Extract< + { + [K in keyof T['attributes']]: T['attributes'][K] extends V ? K : never; + }[keyof T['attributes']], + string +>; + +interface FieldOptions< + T extends + | string + | number + | boolean + | Bytes + | Date + | ParseFile + | ParseGeoPoint + | ParsePolygon + | any[] + | object + | Pointer + | ParseRelation = any, +> { + required?: boolean | undefined; + defaultValue?: T | undefined; + targetClass?: string | undefined; +} + +interface Index { + [fieldName: string]: number | string; +} interface CLPField { '*'?: boolean | undefined; @@ -58,12 +109,6 @@ const FIELD_TYPES = [ 'Relation', ]; -type FieldOptions = { - required?: boolean; - defaultValue?: any; - targetClass?: string; -}; - /** * A Parse.Schema object is for handling schema data from Parse. *

All the schemas methods require MasterKey. @@ -81,7 +126,7 @@ type FieldOptions = { * * @alias Parse.Schema */ -class ParseSchema { +class ParseSchema { className: string; _fields: { [key: string]: any }; _indexes: { [key: string]: any }; @@ -143,7 +188,7 @@ class ParseSchema { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - save() { + save(): Promise { this.assertClassName(); const controller = CoreManager.getSchemaController(); @@ -154,7 +199,7 @@ class ParseSchema { classLevelPermissions: this._clp, }; - return controller.create(this.className, params); + return controller.create(this.className, params) as Promise; } /** @@ -163,7 +208,7 @@ class ParseSchema { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - update() { + update(): Promise { this.assertClassName(); const controller = CoreManager.getSchemaController(); @@ -177,7 +222,7 @@ class ParseSchema { this._fields = {}; this._indexes = {}; - return controller.update(this.className, params); + return controller.update(this.className, params) as Promise; } /** @@ -187,7 +232,7 @@ class ParseSchema { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - delete() { + delete(): Promise { this.assertClassName(); const controller = CoreManager.getSchemaController(); @@ -201,7 +246,7 @@ class ParseSchema { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - purge() { + purge(): Promise { this.assertClassName(); const controller = CoreManager.getSchemaController(); @@ -226,7 +271,7 @@ class ParseSchema { * @param {object | Parse.CLP} clp Class Level Permissions * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - setCLP(clp: PermissionsMap | ParseCLP) { + setCLP(clp: PermissionsMap | ParseCLP): this { if (clp instanceof ParseCLP) { this._clp = clp.toJSON(); } else { @@ -248,9 +293,9 @@ class ParseSchema { * * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addField(name: string, type: string, options: FieldOptions = {}) { - type = type || 'String'; - + addField(name: string, type?: T, options?: FieldOptions): this { + type = (type || 'String') as T; + options = options || {}; if (!name) { throw new Error('field name may not be null.'); } @@ -258,10 +303,10 @@ class ParseSchema { throw new Error(`${type} is not a valid type.`); } if (type === 'Pointer') { - return this.addPointer(name, options.targetClass!, options); + return this.addPointer(name as any, options.targetClass!, options); } if (type === 'Relation') { - return this.addRelation(name, options.targetClass!); + return this.addRelation(name as any, options.targetClass!); } const fieldOptions: Partial & { type: string; @@ -281,7 +326,7 @@ class ParseSchema { }; } } - if (type === 'Bytes') { + if (type === ('Bytes' as T)) { if (options && options.defaultValue) { fieldOptions.defaultValue = { __type: 'Bytes', @@ -304,16 +349,14 @@ class ParseSchema { * schema.addIndex('index_name', { 'field': 1 }); * */ - addIndex(name: string, index: any) { + addIndex(name: string, index: Index): this { if (!name) { throw new Error('index name may not be null.'); } if (!index) { throw new Error('index may not be null.'); } - this._indexes[name] = index; - return this; } @@ -324,7 +367,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addString(name: string, options: FieldOptions) { + addString(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'String', options); } @@ -335,7 +378,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addNumber(name: string, options: FieldOptions) { + addNumber(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Number', options); } @@ -346,7 +389,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addBoolean(name: string, options: FieldOptions) { + addBoolean(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Boolean', options); } @@ -357,7 +400,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addBytes(name: string, options: FieldOptions) { + addBytes(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Bytes', options); } @@ -368,7 +411,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addDate(name: string, options: FieldOptions) { + addDate(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Date', options); } @@ -379,7 +422,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addFile(name: string, options: FieldOptions) { + addFile(name: AttrType, options?: FieldOptions) { return this.addField(name, 'File', options); } @@ -390,7 +433,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addGeoPoint(name: string, options: FieldOptions) { + addGeoPoint(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'GeoPoint', options); } @@ -401,7 +444,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addPolygon(name: string, options: FieldOptions) { + addPolygon(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Polygon', options); } @@ -412,7 +455,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addArray(name: string, options: FieldOptions) { + addArray(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Array', options); } @@ -423,7 +466,7 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addObject(name: string, options: FieldOptions) { + addObject(name: AttrType, options?: FieldOptions): this { return this.addField(name, 'Object', options); } @@ -435,7 +478,11 @@ class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addPointer(name: string, targetClass: string, options: FieldOptions = {}) { + addPointer( + name: AttrType, + targetClass: string, + options?: FieldOptions + ): this { if (!name) { throw new Error('field name may not be null.'); } @@ -446,10 +493,10 @@ class ParseSchema { type: string; } = { type: 'Pointer', targetClass }; - if (typeof options.required === 'boolean') { + if (typeof options?.required === 'boolean') { fieldOptions.required = options.required; } - if (options.defaultValue !== undefined) { + if (options?.defaultValue !== undefined) { fieldOptions.defaultValue = options.defaultValue; if (options.defaultValue instanceof ParseObject) { fieldOptions.defaultValue = options.defaultValue.toPointer(); @@ -466,19 +513,17 @@ class ParseSchema { * @param {string} targetClass Name of the target Pointer Class * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addRelation(name: string, targetClass: string) { + addRelation(name: AttrType, targetClass: string) { if (!name) { throw new Error('field name may not be null.'); } if (!targetClass) { throw new Error('You need to set the targetClass of the Relation.'); } - this._fields[name] = { type: 'Relation', targetClass, }; - return this; } @@ -488,7 +533,7 @@ class ParseSchema { * @param {string} name Name of the field * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - deleteField(name: string) { + deleteField(name: string): this { this._fields[name] = { __op: 'Delete' }; return this; } @@ -499,7 +544,7 @@ class ParseSchema { * @param {string} name Name of the field * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - deleteIndex(name: string) { + deleteIndex(name: string): this { this._indexes[name] = { __op: 'Delete' }; return this; } diff --git a/src/ParseSession.ts b/src/ParseSession.ts index 6395a5b43..ab84f23b9 100644 --- a/src/ParseSession.ts +++ b/src/ParseSession.ts @@ -3,6 +3,7 @@ import isRevocableSession from './isRevocableSession'; import ParseObject, { Attributes } from './ParseObject'; import ParseUser from './ParseUser'; +import type { AttributeKey } from './ParseObject'; import type { RequestOptions, FullOptions } from './RESTController'; /** @@ -21,7 +22,7 @@ class ParseSession extends ParseObject { super('_Session'); if (attributes && typeof attributes === 'object') { try { - this.set(attributes || {}); + this.set((attributes || {}) as any); } catch (_) { throw new Error("Can't create an invalid Session"); } @@ -34,14 +35,14 @@ class ParseSession extends ParseObject { * @returns {string} */ getSessionToken(): string { - const token = this.get('sessionToken'); + const token = this.get('sessionToken' as AttributeKey); if (typeof token === 'string') { return token; } return ''; } - static readOnlyAttributes() { + static readOnlyAttributes(): string[] { return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; } @@ -54,7 +55,7 @@ class ParseSession extends ParseObject { * object after it has been fetched. If there is no current user, the * promise will be rejected. */ - static current(options: FullOptions) { + static current(options?: FullOptions): Promise { const controller = CoreManager.getSessionController(); const sessionOptions = ParseObject._getRequestOptions(options); @@ -63,7 +64,7 @@ class ParseSession extends ParseObject { return Promise.reject('There is no current user.'); } sessionOptions.sessionToken = user.getSessionToken(); - return controller.getSession(sessionOptions); + return controller.getSession(sessionOptions) as Promise; }); } @@ -89,7 +90,7 @@ class ParseSession extends ParseObject { ParseObject.registerSubclass('_Session', ParseSession); const DefaultController = { - getSession(options: RequestOptions): Promise { + getSession(options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); const session = new ParseSession(); diff --git a/src/ParseUser.ts b/src/ParseUser.ts index 558495f0e..730790f4c 100644 --- a/src/ParseUser.ts +++ b/src/ParseUser.ts @@ -4,6 +4,7 @@ import ParseError from './ParseError'; import ParseObject, { Attributes } from './ParseObject'; import Storage from './Storage'; +import type { AttributeKey } from './ParseObject'; import type { RequestOptions, FullOptions } from './RESTController'; export type AuthData = { [key: string]: any }; @@ -41,7 +42,7 @@ class ParseUser extends ParseObject { super('_User'); if (attributes && typeof attributes === 'object') { try { - this.set(attributes || {}); + this.set((attributes || {}) as any); } catch (_) { throw new Error("Can't create an invalid Parse User"); } @@ -59,7 +60,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is resolved when the replacement * token has been fetched. */ - _upgradeToRevocableSession(options: RequestOptions): Promise { + _upgradeToRevocableSession(options?: RequestOptions): Promise { const upgradeOptions = ParseObject._getRequestOptions(options); const controller = CoreManager.getUserController(); return controller.upgradeToRevocableSession(this, upgradeOptions); @@ -82,7 +83,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user is linked */ linkWith( - provider: AuthProvider, + provider: string | AuthProvider, options: { authData?: AuthData }, saveOpts: FullOptions = {} ): Promise { @@ -108,12 +109,12 @@ class ParseUser extends ParseObject { authType = provider.getAuthType(); } if (options && Object.hasOwn(options, 'authData')) { - const authData = this.get('authData') || {}; + const authData = this.get('authData' as AttributeKey) || {}; if (typeof authData !== 'object') { throw new Error('Invalid type: authData field should be an object'); } authData[authType] = options.authData; - const oldAnonymousData = authData.anonymous; + const oldAnonymousData = (authData as any).anonymous; this.stripAnonymity(); const controller = CoreManager.getUserController(); @@ -178,7 +179,7 @@ class ParseUser extends ParseObject { } else { authType = provider.getAuthType(); } - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); if (!provider || !authData || typeof authData !== 'object') { return; } @@ -192,7 +193,7 @@ class ParseUser extends ParseObject { * Synchronizes authData for all providers. */ _synchronizeAllAuthData() { - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); if (typeof authData !== 'object') { return; } @@ -209,7 +210,7 @@ class ParseUser extends ParseObject { if (!this.isCurrent()) { return; } - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); if (typeof authData !== 'object') { return; } @@ -249,7 +250,7 @@ class ParseUser extends ParseObject { } else { authType = provider.getAuthType(); } - const authData = this.get('authData') || {}; + const authData = this.get('authData' as AttributeKey) || {}; if (typeof authData !== 'object') { return false; } @@ -260,7 +261,7 @@ class ParseUser extends ParseObject { * Deauthenticates all providers. */ _logOutWithAll() { - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); if (typeof authData !== 'object') { return; } @@ -296,7 +297,7 @@ class ParseUser extends ParseObject { */ _preserveFieldsOnFetch(): Attributes { return { - sessionToken: this.get('sessionToken'), + sessionToken: this.get('sessionToken' as AttributeKey), }; } @@ -321,7 +322,7 @@ class ParseUser extends ParseObject { } stripAnonymity() { - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); if (authData && typeof authData === 'object' && Object.hasOwn(authData, 'anonymous')) { // We need to set anonymous to null instead of deleting it in order to remove it from Parse. authData.anonymous = null; @@ -330,7 +331,7 @@ class ParseUser extends ParseObject { restoreAnonimity(anonymousData: any) { if (anonymousData) { - const authData = this.get('authData'); + const authData = this.get('authData' as AttributeKey); authData.anonymous = anonymousData; } } @@ -341,7 +342,7 @@ class ParseUser extends ParseObject { * @returns {string} */ getUsername(): string | null { - const username = this.get('username'); + const username = this.get('username' as AttributeKey); if (username == null || typeof username === 'string') { return username; } @@ -355,7 +356,7 @@ class ParseUser extends ParseObject { */ setUsername(username: string) { this.stripAnonymity(); - this.set('username', username); + this.set('username' as AttributeKey, username as any); } /** @@ -364,7 +365,7 @@ class ParseUser extends ParseObject { * @param {string} password User's Password */ setPassword(password: string) { - this.set('password', password); + this.set('password' as AttributeKey, password as any); } /** @@ -373,7 +374,7 @@ class ParseUser extends ParseObject { * @returns {string} User's Email */ getEmail(): string | null { - const email = this.get('email'); + const email = this.get('email' as AttributeKey); if (email == null || typeof email === 'string') { return email; } @@ -387,7 +388,7 @@ class ParseUser extends ParseObject { * @returns {boolean} */ setEmail(email: string) { - return this.set('email', email); + return this.set('email' as AttributeKey, email as any); } /** @@ -398,7 +399,7 @@ class ParseUser extends ParseObject { * @returns {string} the session token, or undefined */ getSessionToken(): string | null { - const token = this.get('sessionToken'); + const token = this.get('sessionToken' as AttributeKey); if (token == null || typeof token === 'string') { return token; } @@ -412,7 +413,7 @@ class ParseUser extends ParseObject { */ authenticated(): boolean { const current = ParseUser.current(); - return !!this.get('sessionToken') && !!current && current.id === this.id; + return !!this.get('sessionToken' as AttributeKey) && !!current && current.id === this.id; } /** @@ -598,12 +599,12 @@ class ParseUser extends ParseObject { * @static * @returns {Parse.User} The currently logged in Parse.User. */ - static current(): ParseUser | null { + static current(): T | null { if (!canUseCurrentUser) { return null; } const controller = CoreManager.getUserController(); - return controller.currentUser(); + return controller.currentUser() as T; } /** @@ -613,12 +614,12 @@ class ParseUser extends ParseObject { * @returns {Promise} A Promise that is resolved with the currently * logged in Parse User */ - static currentAsync(): Promise { + static currentAsync(): Promise { if (!canUseCurrentUser) { return Promise.resolve(null); } const controller = CoreManager.getUserController(); - return controller.currentUserAsync(); + return controller.currentUserAsync() as Promise; } /** @@ -635,12 +636,17 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the signup completes. */ - static signUp(username: string, password: string, attrs: Attributes, options?: FullOptions) { + static signUp( + username: string, + password: string, + attrs: Attributes, + options?: FullOptions + ): Promise { attrs = attrs || {}; attrs.username = username; attrs.password = password; const user = new this(attrs); - return user.signUp({}, options); + return user.signUp({}, options) as Promise; } /** @@ -655,7 +661,11 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static logIn(username: string, password: string, options?: FullOptions) { + static logIn( + username: string, + password: string, + options?: FullOptions + ): Promise { if (typeof username !== 'string') { return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); } else if (typeof password !== 'string') { @@ -663,7 +673,7 @@ class ParseUser extends ParseObject { } const user = new this(); user._finishFetch({ username, password }); - return user.logIn(options); + return user.logIn(options) as Promise; } /** @@ -679,12 +689,12 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static logInWithAdditionalAuth( + static logInWithAdditionalAuth( username: string, password: string, authData: AuthData, options?: FullOptions - ) { + ): Promise { if (typeof username !== 'string') { return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); } @@ -696,7 +706,7 @@ class ParseUser extends ParseObject { } const user = new this(); user._finishFetch({ username, password, authData }); - return user.logIn(options); + return user.logIn(options) as Promise; } /** @@ -709,7 +719,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static loginAs(userId: string) { + static loginAs(userId: string): Promise { if (!userId) { throw new ParseError( ParseError.USERNAME_MISSING, @@ -718,7 +728,7 @@ class ParseUser extends ParseObject { } const controller = CoreManager.getUserController(); const user = new this(); - return controller.loginAs(user, userId); + return controller.loginAs(user, userId) as Promise; } /** @@ -733,7 +743,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static become(sessionToken: string, options?: RequestOptions) { + static become(sessionToken: string, options?: RequestOptions): Promise { if (!canUseCurrentUser) { throw new Error('It is not memory-safe to become a user in a server environment'); } @@ -741,7 +751,7 @@ class ParseUser extends ParseObject { becomeOptions.sessionToken = sessionToken; const controller = CoreManager.getUserController(); const user = new this(); - return controller.become(user, becomeOptions); + return controller.become(user, becomeOptions) as Promise; } /** @@ -753,12 +763,12 @@ class ParseUser extends ParseObject { * @static * @returns {Promise} A promise that is fulfilled with the user is fetched. */ - static me(sessionToken: string, options: RequestOptions = {}) { + static me(sessionToken: string, options?: RequestOptions): Promise { const controller = CoreManager.getUserController(); const meOptions = ParseObject._getRequestOptions(options); meOptions.sessionToken = sessionToken; const user = new this(); - return controller.me(user, meOptions); + return controller.me(user, meOptions) as Promise; } /** @@ -771,10 +781,10 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login completes. */ - static hydrate(userJSON: Attributes) { + static hydrate(userJSON: Attributes): Promise { const controller = CoreManager.getUserController(); const user = new this(); - return controller.hydrate(user, userJSON); + return controller.hydrate(user, userJSON) as Promise; } /** @@ -787,13 +797,13 @@ class ParseUser extends ParseObject { * @static * @returns {Promise} */ - static logInWith( - provider: any, + static logInWith( + provider: string | AuthProvider, options: { authData?: AuthData }, saveOpts?: FullOptions - ): Promise { + ): Promise { const user = new this(); - return user.linkWith(provider, options, saveOpts); + return user.linkWith(provider, options, saveOpts) as Promise; } /** @@ -806,7 +816,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is resolved when the session is * destroyed on the server. */ - static logOut(options: RequestOptions = {}) { + static logOut(options?: RequestOptions): Promise { const controller = CoreManager.getUserController(); return controller.logOut(options); } @@ -826,7 +836,7 @@ class ParseUser extends ParseObject { * @static * @returns {Promise} */ - static requestPasswordReset(email: string, options?: RequestOptions) { + static requestPasswordReset(email: string, options?: RequestOptions): Promise { const requestOptions = ParseObject._getRequestOptions(options); const controller = CoreManager.getUserController(); return controller.requestPasswordReset(email, requestOptions); @@ -845,7 +855,7 @@ class ParseUser extends ParseObject { * @static * @returns {Promise} */ - static requestEmailVerification(email: string, options?: RequestOptions) { + static requestEmailVerification(email: string, options?: RequestOptions): Promise { const requestOptions = ParseObject._getRequestOptions(options); const controller = CoreManager.getUserController(); return controller.requestEmailVerification(email, requestOptions); @@ -862,7 +872,11 @@ class ParseUser extends ParseObject { * the password regardless of whether the email has been verified. This requires the master key. * @returns {Promise} A promise that is fulfilled with a user when the password is correct. */ - static verifyPassword(username: string, password: string, options?: RequestOptions) { + static verifyPassword( + username: string, + password: string, + options?: RequestOptions + ): Promise { if (typeof username !== 'string') { return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); } @@ -872,7 +886,7 @@ class ParseUser extends ParseObject { } const controller = CoreManager.getUserController(); - return controller.verifyPassword(username, password, options || {}); + return controller.verifyPassword(username, password, options || {}) as Promise; } /** @@ -1098,7 +1112,7 @@ const DefaultController = { }); }, - signUp(user: ParseUser, attrs: Attributes, options: RequestOptions): Promise { + signUp(user: ParseUser, attrs: Attributes, options?: RequestOptions): Promise { const username = (attrs && attrs.username) || user.get('username'); const password = (attrs && attrs.password) || user.get('password'); @@ -1124,7 +1138,7 @@ const DefaultController = { }); }, - logIn(user: ParseUser, options: RequestOptions): Promise { + logIn(user: ParseUser, options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); const stateController = CoreManager.getObjectStateController(); const auth = { @@ -1163,7 +1177,7 @@ const DefaultController = { ); }, - become(user: ParseUser, options: RequestOptions): Promise { + become(user: ParseUser, options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'users/me', {}, options).then(response => { user._finishFetch(response); @@ -1182,7 +1196,7 @@ const DefaultController = { } }, - me(user: ParseUser, options: RequestOptions): Promise { + me(user: ParseUser, options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'users/me', {}, options).then(response => { user._finishFetch(response); @@ -1191,9 +1205,9 @@ const DefaultController = { }); }, - logOut(options: RequestOptions): Promise { + logOut(options?: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); - if (options.sessionToken) { + if (options?.sessionToken) { return RESTController.request('POST', 'logout', {}, options); } return DefaultController.currentUserAsync().then(currentUser => { @@ -1216,12 +1230,12 @@ const DefaultController = { }); }, - requestPasswordReset(email: string, options: RequestOptions) { + requestPasswordReset(email: string, options?: RequestOptions) { const RESTController = CoreManager.getRESTController(); return RESTController.request('POST', 'requestPasswordReset', { email }, options); }, - async upgradeToRevocableSession(user: ParseUser, options: RequestOptions) { + async upgradeToRevocableSession(user: ParseUser, options?: RequestOptions) { const token = user.getSessionToken(); if (!token) { return Promise.reject( @@ -1250,7 +1264,7 @@ const DefaultController = { }); }, - verifyPassword(username: string, password: string, options: RequestOptions) { + verifyPassword(username: string, password: string, options?: RequestOptions) { const RESTController = CoreManager.getRESTController(); const data = { username, @@ -1262,7 +1276,7 @@ const DefaultController = { return RESTController.request('GET', 'verifyPassword', data, options); }, - requestEmailVerification(email: string, options: RequestOptions) { + requestEmailVerification(email: string, options?: RequestOptions) { const RESTController = CoreManager.getRESTController(); return RESTController.request('POST', 'verificationEmailRequest', { email }, options); }, diff --git a/src/Push.ts b/src/Push.ts index 2d69980da..18059b626 100644 --- a/src/Push.ts +++ b/src/Push.ts @@ -10,6 +10,8 @@ export type PushData = { push_time?: Date | string; expiration_time?: Date | string; expiration_interval?: number; + data?: any; + channels?: string[]; }; /** diff --git a/types/Cloud.d.ts b/types/Cloud.d.ts index 5fe5a74c5..f7effa1d1 100644 --- a/types/Cloud.d.ts +++ b/types/Cloud.d.ts @@ -30,7 +30,16 @@ import type { RequestOptions } from './RESTController'; * @returns {Promise} A promise that will be resolved with the result * of the function. */ -export declare function run(name: string, data: any, options: RequestOptions): Promise; +export declare function run any>( + name: string, + data?: null, + options?: RequestOptions +): Promise>; +export declare function run< + T extends (param: { + [P in keyof Parameters[0]]: Parameters[0][P]; + }) => any, +>(name: string, data: Parameters[0], options?: RequestOptions): Promise>; /** * Gets data for the current set of cloud jobs. * diff --git a/types/CoreManager.d.ts b/types/CoreManager.d.ts index 2abc0c2c5..4874dd5db 100644 --- a/types/CoreManager.d.ts +++ b/types/CoreManager.d.ts @@ -23,10 +23,10 @@ type AnalyticsController = { ) => Promise; }; type CloudController = { - run: (name: string, data: any, options: RequestOptions) => Promise; - getJobsData: (options: RequestOptions) => Promise; + run: (name: string, data: any, options?: RequestOptions) => Promise; + getJobsData: (options?: RequestOptions) => Promise; /** Returns promise which resolves with JobStatusId of the job */ - startJob: (name: string, data: any, options: RequestOptions) => Promise; + startJob: (name: string, data: any, options?: RequestOptions) => Promise; }; type ConfigController = { current: () => Promise | ParseConfig; @@ -77,15 +77,15 @@ type ObjectController = { fetch: ( object: ParseObject | Array, forceFetch: boolean, - options: RequestOptions + options?: RequestOptions ) => Promise | ParseObject | undefined>; save: ( object: ParseObject | Array | null, - options: RequestOptions + options?: RequestOptions ) => Promise | ParseFile | undefined>; destroy: ( object: ParseObject | Array, - options: RequestOptions + options?: RequestOptions ) => Promise>; }; type ObjectStateController = { @@ -114,7 +114,7 @@ type QueryController = { find( className: string, params: QueryJSON, - options: RequestOptions + options?: RequestOptions ): Promise<{ results?: Array; className?: string; @@ -123,15 +123,49 @@ type QueryController = { aggregate( className: string, params: any, - options: RequestOptions + options?: RequestOptions ): Promise<{ results?: Array; }>; }; -type EventuallyQueue = { - save: (object: ParseObject, serverOptions: SaveOptions) => Promise; - destroy: (object: ParseObject, serverOptions: RequestOptions) => Promise; - poll: (ms?: number) => void; +export type QueueObject = { + queueId: string; + action: string; + object: ParseObject; + serverOptions: SaveOptions | RequestOptions; + id: string; + className: string; + hash: string; + createdAt: Date; +}; +export type Queue = Array; +export type EventuallyQueue = { + save: (object: ParseObject, serverOptions?: SaveOptions) => Promise; + destroy: (object: ParseObject, serverOptions?: RequestOptions) => Promise; + generateQueueId: (action: string, object: ParseObject) => string; + enqueue( + action: string, + object: ParseObject, + serverOptions?: SaveOptions | RequestOptions + ): Promise; + store(data: Queue): Promise; + load(): Promise; + getQueue(): Promise; + setQueue(queue: Queue): Promise; + remove(queueId: string): Promise; + clear(): Promise; + queueItemExists(queue: Queue, queueId: string): number; + length(): Promise; + sendQueue(): Promise; + sendQueueCallback(object: ParseObject, queueObject: QueueObject): Promise; + poll(ms?: number): void; + stopPoll(): void; + isPolling(): boolean; + process: { + create(ObjectType: any, queueObject: any): Promise; + byId(ObjectType: any, queueObject: any): Promise; + byHash(ObjectType: any, queueObject: any): Promise; + }; }; type RESTController = { request: (method: string, path: string, data?: any, options?: RequestOptions) => Promise; @@ -150,10 +184,10 @@ type SchemaController = { delete: (className: string, options?: RequestOptions) => Promise; create: (className: string, params: any, options?: RequestOptions) => Promise; update: (className: string, params: any, options?: RequestOptions) => Promise; - send(className: string, method: string, params: any, options: RequestOptions): Promise; + send(className: string, method: string, params: any, options?: RequestOptions): Promise; }; type SessionController = { - getSession: (token: RequestOptions) => Promise; + getSession: (options?: RequestOptions) => Promise; }; type StorageController = | { @@ -191,24 +225,24 @@ type UserController = { setCurrentUser: (user: ParseUser) => Promise; currentUser: () => ParseUser | null; currentUserAsync: () => Promise; - signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise; - logIn: (user: ParseUser, options: RequestOptions) => Promise; + signUp: (user: ParseUser, attrs: AttributeMap, options?: RequestOptions) => Promise; + logIn: (user: ParseUser, options?: RequestOptions) => Promise; loginAs: (user: ParseUser, userId: string) => Promise; - become: (user: ParseUser, options: RequestOptions) => Promise; + become: (user: ParseUser, options?: RequestOptions) => Promise; hydrate: (user: ParseUser, userJSON: AttributeMap) => Promise; - logOut: (options: RequestOptions) => Promise; - me: (user: ParseUser, options: RequestOptions) => Promise; - requestPasswordReset: (email: string, options: RequestOptions) => Promise; + logOut: (options?: RequestOptions) => Promise; + me: (user: ParseUser, options?: RequestOptions) => Promise; + requestPasswordReset: (email: string, options?: RequestOptions) => Promise; updateUserOnDisk: (user: ParseUser) => Promise; - upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => Promise; + upgradeToRevocableSession: (user: ParseUser, options?: RequestOptions) => Promise; linkWith: (user: ParseUser, authData: AuthData, options?: FullOptions) => Promise; removeUserFromDisk: () => Promise; verifyPassword: ( username: string, password: string, - options: RequestOptions + options?: RequestOptions ) => Promise; - requestEmailVerification: (email: string, options: RequestOptions) => Promise; + requestEmailVerification: (email: string, options?: RequestOptions) => Promise; }; type HooksController = { get: (type: string, functionName?: string, triggerName?: string) => Promise; diff --git a/types/EventuallyQueue.d.ts b/types/EventuallyQueue.d.ts index 78d76d077..5c620cc81 100644 --- a/types/EventuallyQueue.d.ts +++ b/types/EventuallyQueue.d.ts @@ -1,17 +1,7 @@ import ParseObject from './ParseObject'; +import type { Queue, QueueObject } from './CoreManager'; import type { SaveOptions } from './ParseObject'; import type { RequestOptions } from './RESTController'; -type QueueObject = { - queueId: string; - action: string; - object: ParseObject; - serverOptions: SaveOptions | RequestOptions; - id: string; - className: string; - hash: string; - createdAt: Date; -}; -type Queue = Array; /** * Provides utility functions to queue objects that will be * saved to the server at a later date. @@ -67,19 +57,19 @@ declare const EventuallyQueue: { enqueue( action: string, object: ParseObject, - serverOptions: SaveOptions | RequestOptions + serverOptions?: SaveOptions | RequestOptions ): Promise; - store(data: QueueObject[]): Promise; - load(): Promise; + store(data: Queue): Promise; + load(): Promise; /** * Sets the in-memory queue from local storage and returns. * * @function getQueue * @name Parse.EventuallyQueue.getQueue - * @returns {Promise} + * @returns {Promise} * @static */ - getQueue(): Promise; + getQueue(): Promise; /** * Saves the queue to local storage * diff --git a/types/LiveQuerySubscription.d.ts b/types/LiveQuerySubscription.d.ts index 0008a4eee..7e41af0ed 100644 --- a/types/LiveQuerySubscription.d.ts +++ b/types/LiveQuerySubscription.d.ts @@ -1,4 +1,5 @@ import type ParseQuery from './ParseQuery'; +import type { EventEmitter } from 'events'; /** * Creates a new LiveQuery Subscription. * cloud functions. @@ -88,9 +89,9 @@ declare class LiveQuerySubscription { subscribePromise: any; unsubscribePromise: any; subscribed: boolean; - emitter: any; - on: any; - emit: any; + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; constructor(id: string | number, query: ParseQuery, sessionToken?: string); /** * Close the subscription diff --git a/types/Parse.d.ts b/types/Parse.d.ts index 55237e7ff..b5fabe2ff 100644 --- a/types/Parse.d.ts +++ b/types/Parse.d.ts @@ -1,4 +1,3 @@ -import EventuallyQueue from './EventuallyQueue'; import * as ParseOp from './ParseOp'; import ACL from './ParseACL'; import * as Analytics from './Analytics'; @@ -21,6 +20,7 @@ import Session from './ParseSession'; import User from './ParseUser'; import ParseLiveQuery from './ParseLiveQuery'; import LiveQueryClient from './LiveQueryClient'; +import type { EventuallyQueue } from './CoreManager'; declare const Parse: { ACL: typeof ACL; Analytics: typeof Analytics; @@ -65,26 +65,26 @@ declare const Parse: { run: ( name: string, data: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; - getJobsData: (options: import('./RESTController').RequestOptions) => Promise; + getJobsData: (options?: import('./RESTController').RequestOptions) => Promise; startJob: ( name: string, data: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; }): void; getCloudController(): { run: ( name: string, data: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; - getJobsData: (options: import('./RESTController').RequestOptions) => Promise; + getJobsData: (options?: import('./RESTController').RequestOptions) => Promise; startJob: ( name: string, data: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; }; setConfigController(controller: { @@ -149,28 +149,8 @@ declare const Parse: { } ) => Promise; }): void; - setEventuallyQueue(controller: { - save: ( - object: ParseObject, - serverOptions: import('./ParseObject').SaveOptions - ) => Promise; - destroy: ( - object: ParseObject, - serverOptions: import('./RESTController').RequestOptions - ) => Promise; - poll: (ms?: number) => void; - }): void; - getEventuallyQueue(): { - save: ( - object: ParseObject, - serverOptions: import('./ParseObject').SaveOptions - ) => Promise; - destroy: ( - object: ParseObject, - serverOptions: import('./RESTController').RequestOptions - ) => Promise; - poll: (ms?: number) => void; - }; + setEventuallyQueue(controller: EventuallyQueue): void; + getEventuallyQueue(): EventuallyQueue; getFileController(): { saveFile: ( name: string, @@ -215,30 +195,30 @@ declare const Parse: { fetch: ( object: ParseObject | Array, forceFetch: boolean, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise | ParseObject | undefined>; save: ( object: ParseObject | Array | null, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise | File | undefined>; destroy: ( object: ParseObject | Array, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise>; }): void; getObjectController(): { fetch: ( object: ParseObject | Array, forceFetch: boolean, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise | ParseObject | undefined>; save: ( object: ParseObject | Array | null, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise | File | undefined>; destroy: ( object: ParseObject | Array, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise>; }; setObjectStateController(controller: { @@ -301,7 +281,7 @@ declare const Parse: { find( className: string, params: import('./ParseQuery').QueryJSON, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise<{ results?: Array; className?: string; @@ -310,7 +290,7 @@ declare const Parse: { aggregate( className: string, params: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise<{ results?: Array; }>; @@ -319,7 +299,7 @@ declare const Parse: { find( className: string, params: import('./ParseQuery').QueryJSON, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise<{ results?: Array; className?: string; @@ -328,7 +308,7 @@ declare const Parse: { aggregate( className: string, params: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise<{ results?: Array; }>; @@ -386,7 +366,7 @@ declare const Parse: { className: string, method: string, params: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise; }): void; getSchemaController(): { @@ -410,14 +390,14 @@ declare const Parse: { className: string, method: string, params: any, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ): Promise; }; setSessionController(controller: { - getSession: (token: import('./RESTController').RequestOptions) => Promise; + getSession: (options?: import('./RESTController').RequestOptions) => Promise; }): void; getSessionController(): { - getSession: (token: import('./RESTController').RequestOptions) => Promise; + getSession: (options?: import('./RESTController').RequestOptions) => Promise; }; setStorageController( controller: @@ -584,25 +564,25 @@ declare const Parse: { signUp: ( user: User, attrs: import('./ObjectStateMutations').AttributeMap, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; - logIn: (user: User, options: import('./RESTController').RequestOptions) => Promise; + logIn: (user: User, options?: import('./RESTController').RequestOptions) => Promise; loginAs: (user: User, userId: string) => Promise; - become: (user: User, options: import('./RESTController').RequestOptions) => Promise; + become: (user: User, options?: import('./RESTController').RequestOptions) => Promise; hydrate: ( user: User, userJSON: import('./ObjectStateMutations').AttributeMap ) => Promise; - logOut: (options: import('./RESTController').RequestOptions) => Promise; - me: (user: User, options: import('./RESTController').RequestOptions) => Promise; + logOut: (options?: import('./RESTController').RequestOptions) => Promise; + me: (user: User, options?: import('./RESTController').RequestOptions) => Promise; requestPasswordReset: ( email: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; updateUserOnDisk: (user: User) => Promise; upgradeToRevocableSession: ( user: User, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; linkWith: ( user: User, @@ -613,11 +593,11 @@ declare const Parse: { verifyPassword: ( username: string, password: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; requestEmailVerification: ( email: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; }): void; getUserController(): { @@ -627,25 +607,25 @@ declare const Parse: { signUp: ( user: User, attrs: import('./ObjectStateMutations').AttributeMap, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; - logIn: (user: User, options: import('./RESTController').RequestOptions) => Promise; + logIn: (user: User, options?: import('./RESTController').RequestOptions) => Promise; loginAs: (user: User, userId: string) => Promise; - become: (user: User, options: import('./RESTController').RequestOptions) => Promise; + become: (user: User, options?: import('./RESTController').RequestOptions) => Promise; hydrate: ( user: User, userJSON: import('./ObjectStateMutations').AttributeMap ) => Promise; - logOut: (options: import('./RESTController').RequestOptions) => Promise; - me: (user: User, options: import('./RESTController').RequestOptions) => Promise; + logOut: (options?: import('./RESTController').RequestOptions) => Promise; + me: (user: User, options?: import('./RESTController').RequestOptions) => Promise; requestPasswordReset: ( email: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; updateUserOnDisk: (user: User) => Promise; upgradeToRevocableSession: ( user: User, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; linkWith: ( user: User, @@ -656,11 +636,11 @@ declare const Parse: { verifyPassword: ( username: string, password: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; requestEmailVerification: ( email: string, - options: import('./RESTController').RequestOptions + options?: import('./RESTController').RequestOptions ) => Promise; }; setLiveQueryController(controller: { @@ -769,12 +749,11 @@ declare const Parse: { IndexedDB: any; Hooks: any; Parse: any; - get EventuallyQueue(): any; /** * @member {EventuallyQueue} Parse.EventuallyQueue * @static */ - set EventuallyQueue(queue: typeof EventuallyQueue); + EventuallyQueue: EventuallyQueue; /** * Call this method first to set up your authentication tokens for Parse. * @@ -889,7 +868,7 @@ declare const Parse: { * @static * @returns {boolean} */ - isLocalDatastoreEnabled(): any; + isLocalDatastoreEnabled(): boolean; /** * Gets all contents from Local Datastore * diff --git a/types/ParseFile.d.ts b/types/ParseFile.d.ts index d7eab6ba3..fd99e5b54 100644 --- a/types/ParseFile.d.ts +++ b/types/ParseFile.d.ts @@ -43,8 +43,8 @@ declare class ParseFile { _previousSave?: Promise; _data?: string; _requestTask?: any; - _metadata?: object; - _tags?: object; + _metadata?: Record; + _tags?: Record; /** * @param name {String} The file's name. This will be prefixed by a unique * value once the file has finished saving. The file name must begin with @@ -106,13 +106,13 @@ declare class ParseFile { * * @returns {object} */ - metadata(): object; + metadata(): Record; /** * Gets the tags of the file. * * @returns {object} */ - tags(): object; + tags(): Record; /** * Saves the file to the Parse cloud. * @@ -168,7 +168,7 @@ declare class ParseFile { * * @param {object} metadata Key value pairs to be stored with file object */ - setMetadata(metadata: any): void; + setMetadata(metadata: Record): void; /** * Sets metadata to be saved with file object. Adds to existing metadata. * @@ -181,7 +181,7 @@ declare class ParseFile { * * @param {object} tags Key value pairs to be stored with file object */ - setTags(tags: any): void; + setTags(tags: Record): void; /** * Sets tags to be saved with file object. Adds to existing tags. * diff --git a/types/ParseGeoPoint.d.ts b/types/ParseGeoPoint.d.ts index 0d8271878..e2fda0256 100644 --- a/types/ParseGeoPoint.d.ts +++ b/types/ParseGeoPoint.d.ts @@ -30,7 +30,7 @@ declare class ParseGeoPoint { */ constructor( arg1?: - | Array + | [number, number] | { latitude: number; longitude: number; diff --git a/types/ParseInstallation.d.ts b/types/ParseInstallation.d.ts index 28cf2a661..f9ca0c686 100644 --- a/types/ParseInstallation.d.ts +++ b/types/ParseInstallation.d.ts @@ -30,7 +30,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get appIdentifier(): any; + get appIdentifier(): T[Extract]; /** * The version string of the client application to which this installation belongs. * @@ -38,7 +38,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get appVersion(): any; + get appVersion(): T[Extract]; /** * The display name of the client application to which this installation belongs. * @@ -46,7 +46,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get appName(): any; + get appName(): T[Extract]; /** * The current value of the icon badge for iOS apps. * Changes to this value on the server will be used @@ -56,7 +56,7 @@ declare class ParseInstallation extends Parse * @static * @returns {number} */ - get badge(): any; + get badge(): T[Extract]; /** * An array of the channels to which a device is currently subscribed. * @@ -64,7 +64,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string[]} */ - get channels(): any; + get channels(): T[Extract]; /** * Token used to deliver push notifications to the device. * @@ -72,7 +72,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get deviceToken(): any; + get deviceToken(): T[Extract]; /** * The type of device, “ios”, “android”, “web”, etc. * @@ -80,7 +80,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get deviceType(): any; + get deviceType(): T[Extract]; /** * Gets the GCM sender identifier for this installation * @@ -88,7 +88,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get GCMSenderId(): any; + get GCMSenderId(): T[Extract]; /** * Universally Unique Identifier (UUID) for the device used by Parse. It must be unique across all of an app’s installations. * @@ -96,7 +96,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get installationId(): any; + get installationId(): T[Extract]; /** * Gets the local identifier for this installation * @@ -104,7 +104,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get localeIdentifier(): any; + get localeIdentifier(): T[Extract]; /** * Gets the parse server version for this installation * @@ -112,7 +112,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get parseVersion(): any; + get parseVersion(): T[Extract]; /** * This field is reserved for directing Parse to the push delivery network to be used. * @@ -120,7 +120,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get pushType(): any; + get pushType(): T[Extract]; /** * Gets the time zone for this installation * @@ -128,7 +128,7 @@ declare class ParseInstallation extends Parse * @static * @returns {string} */ - get timeZone(): any; + get timeZone(): T[Extract]; /** * Returns the device types for used for Push Notifications. * diff --git a/types/ParseLiveQuery.d.ts b/types/ParseLiveQuery.d.ts index ac9aa3495..d76898230 100644 --- a/types/ParseLiveQuery.d.ts +++ b/types/ParseLiveQuery.d.ts @@ -1,3 +1,4 @@ +import type { EventEmitter } from 'events'; /** * We expose three events to help you monitor the status of the WebSocket connection: * @@ -26,9 +27,9 @@ * @static */ declare class LiveQuery { - emitter: any; - on: any; - emit: any; + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; constructor(); /** * After open is called, the LiveQuery will try to send a connect request diff --git a/types/ParseObject.d.ts b/types/ParseObject.d.ts index db6233798..f4852d46a 100644 --- a/types/ParseObject.d.ts +++ b/types/ParseObject.d.ts @@ -31,8 +31,10 @@ type FetchOptions = { context?: AttributeMap; }; export type SetOptions = { - ignoreValidation: boolean; + ignoreValidation?: boolean; + unset?: boolean; }; +export type AttributeKey = Extract; export interface Attributes { [key: string]: any; } @@ -41,6 +43,12 @@ interface JSONBaseAttributes { createdAt: string; updatedAt: string; } +interface CommonAttributes { + ACL: ParseACL; +} +type AtomicKey = { + [K in keyof T]: NonNullable extends any[] ? K : never; +}; type Encode = T extends ParseObject ? ReturnType | Pointer : T extends ParseACL | ParseGeoPoint | ParsePolygon | ParseRelation | ParseFile @@ -92,7 +100,7 @@ declare class ParseObject { className: string; [attr: string]: any; }, - attributes?: T | Attributes, + attributes?: T, options?: SetOptions ); /** @@ -178,7 +186,7 @@ declare class ParseObject { * @param {object} other - An other object ot compare * @returns {boolean} */ - equals(other: any): boolean; + equals(other: T): boolean; /** * Returns true if this object has been modified since its last * save/refresh. If an attribute is specified, it returns true only if that @@ -187,13 +195,13 @@ declare class ParseObject { * @param {string} attr An attribute name (optional). * @returns {boolean} */ - dirty(attr?: string): boolean; + dirty>(attr?: K): boolean; /** * Returns an array of keys that have been modified since last save/refresh * * @returns {string[]} */ - dirtyKeys(): Array; + dirtyKeys(): string[]; /** * Returns true if the object has been fetched. * @@ -218,14 +226,14 @@ declare class ParseObject { * @param {string} attr The string name of an attribute. * @returns {*} */ - get(attr: string): any; + get>(attr: K): T[K]; /** * Gets a relation on the given class for the attribute. * * @param {string} attr The attribute to get the relation for. * @returns {Parse.Relation} */ - relation = Extract>( + relation = AttributeKey>( attr: T[K] extends ParseRelation ? K : never ): ParseRelation; /** @@ -234,7 +242,7 @@ declare class ParseObject { * @param {string} attr The string name of an attribute. * @returns {string} */ - escape(attr: string): string; + escape>(attr: K): string; /** * Returns true if the attribute contains a value that is not * null or undefined. @@ -242,7 +250,7 @@ declare class ParseObject { * @param {string} attr The string name of the attribute. * @returns {boolean} */ - has(attr: string): boolean; + has>(attr: K): boolean; /** * Sets a hash of model attributes on the object. * @@ -273,7 +281,11 @@ declare class ParseObject { * The only supported option is error. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - set(key: any, value?: any, options?: any): this; + set>( + key: K | (Pick | T), + value?: SetOptions | (T[K] extends undefined ? never : T[K]), + options?: SetOptions + ): this; /** * Remove an attribute from the model. This is a noop if the attribute doesn't * exist. @@ -282,12 +294,7 @@ declare class ParseObject { * @param options * @returns {Parse.Object} Returns the object, so you can chain this call. */ - unset( - attr: string, - options?: { - [opt: string]: any; - } - ): this; + unset>(attr: K, options?: SetOptions): this; /** * Atomically increments the value of the given attribute the next time the * object is saved. If no amount is specified, 1 is used by default. @@ -296,7 +303,7 @@ declare class ParseObject { * @param amount {Number} The amount to increment by (optional). * @returns {Parse.Object} Returns the object, so you can chain this call. */ - increment(attr: string, amount?: number): this; + increment>(attr: K, amount?: number): this; /** * Atomically decrements the value of the given attribute the next time the * object is saved. If no amount is specified, 1 is used by default. @@ -305,7 +312,7 @@ declare class ParseObject { * @param amount {Number} The amount to decrement by (optional). * @returns {Parse.Object} Returns the object, so you can chain this call. */ - decrement(attr: string, amount?: number): this; + decrement>(attr: K, amount?: number): this; /** * Atomically add an object to the end of the array associated with a given * key. @@ -314,7 +321,7 @@ declare class ParseObject { * @param item {} The item to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - add(attr: string, item: any): this; + add[keyof T]>(attr: K, item: NonNullable[number]): this; /** * Atomically add the objects to the end of the array associated with a given * key. @@ -323,7 +330,7 @@ declare class ParseObject { * @param items {Object[]} The items to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addAll(attr: string, items: Array): this; + addAll[keyof T]>(attr: K, items: NonNullable): this; /** * Atomically add an object to the array associated with a given key, only * if it is not already present in the array. The position of the insert is @@ -333,7 +340,7 @@ declare class ParseObject { * @param item {} The object to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addUnique(attr: string, item: any): this; + addUnique[keyof T]>(attr: K, item: NonNullable[number]): this; /** * Atomically add the objects to the array associated with a given key, only * if it is not already present in the array. The position of the insert is @@ -343,7 +350,7 @@ declare class ParseObject { * @param items {Object[]} The objects to add. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - addAllUnique(attr: string, items: Array): this; + addAllUnique[keyof T]>(attr: K, items: NonNullable): this; /** * Atomically remove all instances of an object from the array associated * with a given key. @@ -352,7 +359,7 @@ declare class ParseObject { * @param item {} The object to remove. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - remove(attr: string, item: any): this; + remove[keyof T]>(attr: K, item: NonNullable[number]): this; /** * Atomically remove all instances of the objects from the array associated * with a given key. @@ -361,7 +368,7 @@ declare class ParseObject { * @param items {Object[]} The object to remove. * @returns {Parse.Object} Returns the object, so you can chain this call. */ - removeAll(attr: string, items: Array): this; + removeAll[keyof T]>(attr: K, items: NonNullable): this; /** * Returns an instance of a subclass of Parse.Op describing what kind of * modification has been performed on this field since the last time it was @@ -371,7 +378,7 @@ declare class ParseObject { * @param attr {String} The key. * @returns {Parse.Op | undefined} The operation, or undefined if none. */ - op(attr: string): Op | undefined; + op>(attr: K): Op | undefined; /** * Creates a new model with identical attributes to this one. * @@ -449,7 +456,7 @@ declare class ParseObject { * * @param {string} [keys] - specify which fields to revert */ - revert(...keys: Array): void; + revert(...keys: Array>): void; /** * Clears all attributes on a model * @@ -520,7 +527,7 @@ declare class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - saveEventually(options: SaveOptions): Promise; + saveEventually(options?: SaveOptions): Promise; /** * Set a hash of model attributes, and save the model to the server. * updatedAt will be updated when the request returns. @@ -584,17 +591,7 @@ declare class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - save( - arg1?: - | undefined - | string - | { - [attr: string]: any; - } - | null, - arg2?: SaveOptions | any, - arg3?: SaveOptions - ): Promise; + save>(arg1?: Pick | T | null, arg2?: SaveOptions): Promise; /** * Deletes this object from the server at some unspecified time in the future, * even if Parse is currently inaccessible. @@ -617,7 +614,7 @@ declare class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - destroyEventually(options: RequestOptions): Promise; + destroyEventually(options?: RequestOptions): Promise; /** * Destroy this model on the server if it was already persisted. * @@ -632,7 +629,7 @@ declare class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - destroy(options: RequestOptions): Promise; + destroy(options?: RequestOptions): Promise; /** * Asynchronously stores the object and every object it points to in the local datastore, * recursively, using a default pin name: _default. @@ -771,7 +768,7 @@ declare class ParseObject { */ static fetchAllWithInclude( list: T[], - keys: string | Array>, + keys: keyof T['attributes'] | Array, options?: RequestOptions ): Promise; /** @@ -806,7 +803,7 @@ declare class ParseObject { */ static fetchAllIfNeededWithInclude( list: T[], - keys: string | Array>, + keys: keyof T['attributes'] | Array, options?: RequestOptions ): Promise; /** @@ -952,7 +949,7 @@ declare class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference */ - static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject; + static fromJSON(json: any, override?: boolean, dirty?: boolean): T; /** * Registers a subclass of Parse.Object with a specific class name. * When objects of that class are retrieved from a query, they will be diff --git a/types/ParseQuery.d.ts b/types/ParseQuery.d.ts index dbd841983..52564d74d 100644 --- a/types/ParseQuery.d.ts +++ b/types/ParseQuery.d.ts @@ -2,6 +2,7 @@ import ParseGeoPoint from './ParseGeoPoint'; import ParseObject from './ParseObject'; import type LiveQuerySubscription from './LiveQuerySubscription'; import type { FullOptions } from './RESTController'; +import type { Pointer } from './ParseObject'; type BatchOptions = FullOptions & { batchSize?: number; useMasterKey?: boolean; @@ -45,6 +46,11 @@ export type QueryJSON = { subqueryReadPreference?: string; comment?: string; }; +interface BaseAttributes { + createdAt: Date; + objectId: string; + updatedAt: Date; +} /** * Creates a new parse Parse.Query for the given Parse.Object subclass. * @@ -147,7 +153,11 @@ declare class ParseQuery { * @param value * @returns {Parse.Query} */ - _addCondition(key: string, condition: string, value: any): this; + _addCondition( + key: K, + condition: string, + value: any + ): this; /** * Converts string for regular expression at the beginning * @@ -267,12 +277,12 @@ declare class ParseQuery { * @param {string} [options.sessionToken] A valid session token, used for making a request on behalf of a specific user. * @returns {Promise} A promise that is resolved with the query completes. */ - distinct( - key: string, + distinct( + key: K, options?: { sessionToken?: string; } - ): Promise>; + ): Promise; /** * Executes an aggregate query and returns aggregate results * @@ -452,13 +462,15 @@ declare class ParseQuery { * @param value The value that the Parse.Object must contain. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - equalTo( - key: - | string - | { - [key: string]: any; - }, - value?: any + equalTo( + key: K, + value: + | T['attributes'][K] + | (T['attributes'][K] extends ParseObject + ? Pointer + : T['attributes'][K] extends Array + ? E + : never) ): this; /** * Adds a constraint to the query that requires a particular key's value to @@ -468,13 +480,15 @@ declare class ParseQuery { * @param value The value that must not be equalled. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notEqualTo( - key: - | string - | { - [key: string]: any; - }, - value?: any + notEqualTo( + key: K, + value: + | T['attributes'][K] + | (T['attributes'][K] extends ParseObject + ? Pointer + : T['attributes'][K] extends Array + ? E + : never) ): this; /** * Adds a constraint to the query that requires a particular key's value to @@ -484,7 +498,10 @@ declare class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThan(key: string, value: any): this; + lessThan( + key: K, + value: T['attributes'][K] + ): this; /** * Adds a constraint to the query that requires a particular key's value to * be greater than the provided value. @@ -493,7 +510,10 @@ declare class ParseQuery { * @param value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThan(key: string, value: any): this; + greaterThan( + key: K, + value: T['attributes'][K] + ): this; /** * Adds a constraint to the query that requires a particular key's value to * be less than or equal to the provided value. @@ -502,7 +522,10 @@ declare class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThanOrEqualTo(key: string, value: any): this; + lessThanOrEqualTo( + key: K, + value: T['attributes'][K] + ): this; /** * Adds a constraint to the query that requires a particular key's value to * be greater than or equal to the provided value. @@ -511,25 +534,34 @@ declare class ParseQuery { * @param {*} value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThanOrEqualTo(key: string, value: any): this; + greaterThanOrEqualTo( + key: K, + value: T['attributes'][K] + ): this; /** * Adds a constraint to the query that requires a particular key's value to * be contained in the provided list of values. * * @param {string} key The key to check. - * @param {Array<*>} value The values that will match. + * @param {Array<*>} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedIn(key: string, value: Array): this; + containedIn( + key: K, + values: Array + ): this; /** * Adds a constraint to the query that requires a particular key's value to * not be contained in the provided list of values. * * @param {string} key The key to check. - * @param {Array<*>} value The values that will not match. + * @param {Array<*>} values The values that will not match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notContainedIn(key: string, value: Array): this; + notContainedIn( + key: K, + values: Array + ): this; /** * Adds a constraint to the query that requires a particular key's value to * be contained by the provided list of values. Get objects where all array elements match. @@ -538,7 +570,10 @@ declare class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedBy(key: string, values: Array): this; + containedBy( + key: K, + values: Array + ): this; /** * Adds a constraint to the query that requires a particular key's value to * contain each one of the provided list of values. @@ -547,7 +582,7 @@ declare class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containsAll(key: string, values: Array): this; + containsAll(key: K, values: any[]): this; /** * Adds a constraint to the query that requires a particular key's value to * contain each one of the provided list of values starting with given strings. @@ -556,21 +591,24 @@ declare class ParseQuery { * @param {Array} values The string values that will match as starting string. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containsAllStartingWith(key: string, values: Array): this; + containsAllStartingWith( + key: K, + values: any[] + ): this; /** * Adds a constraint for finding objects that contain the given key. * * @param {string} key The key that should exist. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - exists(key: string): this; + exists(key: K): this; /** * Adds a constraint for finding objects that do not contain a given key. * * @param {string} key The key that should not exist * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotExist(key: string): this; + doesNotExist(key: K): this; /** * Adds a regular expression constraint for finding string values that match * the provided regular expression. @@ -581,7 +619,11 @@ declare class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matches(key: string, regex: RegExp | string, modifiers?: string): this; + matches( + key: K, + regex: RegExp | string, + modifiers?: string + ): this; /** * Adds a constraint that requires that a key's value matches a Parse.Query * constraint. @@ -591,7 +633,10 @@ declare class ParseQuery { * @param {Parse.Query} query The query that should match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matchesQuery(key: string, query: ParseQuery): this; + matchesQuery( + key: K, + query: ParseQuery + ): this; /** * Adds a constraint that requires that a key's value not matches a * Parse.Query constraint. @@ -601,7 +646,10 @@ declare class ParseQuery { * @param {Parse.Query} query The query that should not match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotMatchQuery(key: string, query: ParseQuery): this; + doesNotMatchQuery( + key: K, + query: ParseQuery + ): this; /** * Adds a constraint that requires that a key's value matches a value in * an object returned by a different Parse.Query. @@ -613,7 +661,11 @@ declare class ParseQuery { * @param {Parse.Query} query The query to run. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matchesKeyInQuery(key: string, queryKey: string, query: ParseQuery): this; + matchesKeyInQuery< + U extends ParseObject, + K extends keyof T['attributes'], + X extends Extract, + >(key: K, queryKey: X, query: ParseQuery): this; /** * Adds a constraint that requires that a key's value not match a value in * an object returned by a different Parse.Query. @@ -625,7 +677,11 @@ declare class ParseQuery { * @param {Parse.Query} query The query to run. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - doesNotMatchKeyInQuery(key: string, queryKey: string, query: ParseQuery): this; + doesNotMatchKeyInQuery< + U extends ParseObject, + K extends keyof T['attributes'] | keyof BaseAttributes, + X extends Extract, + >(key: K, queryKey: X, query: ParseQuery): this; /** * Adds a constraint for finding string values that contain a provided * string. This may be slow for large datasets. @@ -634,7 +690,7 @@ declare class ParseQuery { * @param {string} substring The substring that the value must contain. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - contains(key: string, substring: string): this; + contains(key: K, substring: string): this; /** * Adds a constraint for finding string values that contain a provided * string. This may be slow for large datasets. Requires Parse-Server > 2.5.0 @@ -664,7 +720,11 @@ declare class ParseQuery { * @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - fullText(key: string, value: string, options?: FullTextQueryOptions): this; + fullText( + key: K, + value: string, + options?: FullTextQueryOptions + ): this; /** * Method to sort the full text search by text score * @@ -681,7 +741,11 @@ declare class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - startsWith(key: string, prefix: string, modifiers?: string): this; + startsWith( + key: K, + prefix: string, + modifiers?: string + ): this; /** * Adds a constraint for finding string values that end with a provided * string. This will be slow for large datasets. @@ -691,7 +755,11 @@ declare class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - endsWith(key: string, suffix: string, modifiers?: string): this; + endsWith( + key: K, + suffix: string, + modifiers?: string + ): this; /** * Adds a proximity based constraint for finding objects with key point * values near the point given. @@ -700,7 +768,7 @@ declare class ParseQuery { * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - near(key: string, point: ParseGeoPoint): this; + near(key: K, point: ParseGeoPoint): this; /** * Adds a proximity based constraint for finding objects with key point * values near the point given and within the maximum distance given. @@ -713,7 +781,12 @@ declare class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinRadians(key: string, point: ParseGeoPoint, maxDistance: number, sorted?: boolean): this; + withinRadians( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this; /** * Adds a proximity based constraint for finding objects with key point * values near the point given and within the maximum distance given. @@ -727,7 +800,12 @@ declare class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinMiles(key: string, point: ParseGeoPoint, maxDistance: number, sorted: boolean): this; + withinMiles( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this; /** * Adds a proximity based constraint for finding objects with key point * values near the point given and within the maximum distance given. @@ -741,7 +819,12 @@ declare class ParseQuery { * defaults to true. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinKilometers(key: string, point: ParseGeoPoint, maxDistance: number, sorted: boolean): this; + withinKilometers( + key: K, + point: ParseGeoPoint, + maxDistance: number, + sorted?: boolean + ): this; /** * Adds a constraint to the query that requires a particular key's * coordinates be contained within a given rectangular geographic bounding @@ -754,7 +837,11 @@ declare class ParseQuery { * The upper-right inclusive corner of the box. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinGeoBox(key: string, southwest: ParseGeoPoint, northeast: ParseGeoPoint): this; + withinGeoBox( + key: K, + southwest: ParseGeoPoint, + northeast: ParseGeoPoint + ): this; /** * Adds a constraint to the query that requires a particular key's * coordinates be contained within and on the bounds of a given polygon. @@ -766,7 +853,10 @@ declare class ParseQuery { * @param {Array} points Array of Coordinates / GeoPoints * @returns {Parse.Query} Returns the query, so you can chain this call. */ - withinPolygon(key: string, points: Array>): this; + withinPolygon( + key: K, + points: number[][] + ): this; /** * Add a constraint to the query that requires a particular key's * coordinates that contains a ParseGeoPoint @@ -775,7 +865,10 @@ declare class ParseQuery { * @param {Parse.GeoPoint} point * @returns {Parse.Query} Returns the query, so you can chain this call. */ - polygonContains(key: string, point: ParseGeoPoint): this; + polygonContains( + key: K, + point: ParseGeoPoint + ): this; /** * Sorts the results in ascending order by the given key. * @@ -847,7 +940,9 @@ declare class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to include. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - include(...keys: Array>): this; + include( + ...keys: Array> + ): this; /** * Includes all nested Parse.Objects one level deep. * @@ -864,7 +959,9 @@ declare class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to include. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - select(...keys: Array>): this; + select( + ...keys: Array> + ): this; /** * Restricts the fields of the returned Parse.Objects to all keys except the * provided keys. Exclude takes precedence over select and include. @@ -874,7 +971,9 @@ declare class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to exclude. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - exclude(...keys: Array>): this; + exclude( + ...keys: Array> + ): this; /** * Restricts live query to trigger only for watched fields. * @@ -883,7 +982,7 @@ declare class ParseQuery { * @param {...string|Array} keys The name(s) of the key(s) to watch. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - watch(...keys: Array>): this; + watch(...keys: Array>): this; /** * Changes the read preference that the backend will use when performing the query to the database. * diff --git a/types/ParseSchema.d.ts b/types/ParseSchema.d.ts index 4533e02ec..6adb2935e 100644 --- a/types/ParseSchema.d.ts +++ b/types/ParseSchema.d.ts @@ -1,5 +1,53 @@ +import ParseObject from './ParseObject'; import ParseCLP from './ParseCLP'; +import type ParseGeoPoint from './ParseGeoPoint'; +import type ParseFile from './ParseFile'; +import type ParsePolygon from './ParsePolygon'; +import type ParseRelation from './ParseRelation'; import type { PermissionsMap } from './ParseCLP'; +import type { Pointer } from './ParseObject'; +type Bytes = string; +type TYPE = + | 'String' + | 'Number' + | 'Bytes' + | 'Boolean' + | 'Date' + | 'File' + | 'GeoPoint' + | 'Polygon' + | 'Array' + | 'Object' + | 'Pointer' + | 'Relation'; +type AttrType = Extract< + { + [K in keyof T['attributes']]: T['attributes'][K] extends V ? K : never; + }[keyof T['attributes']], + string +>; +interface FieldOptions< + T extends + | string + | number + | boolean + | Bytes + | Date + | ParseFile + | ParseGeoPoint + | ParsePolygon + | any[] + | object + | Pointer + | ParseRelation = any, +> { + required?: boolean | undefined; + defaultValue?: T | undefined; + targetClass?: string | undefined; +} +interface Index { + [fieldName: string]: number | string; +} interface CLPField { '*'?: boolean | undefined; requiresAuthentication?: boolean | undefined; @@ -36,11 +84,6 @@ interface RestSchema { }; }; } -type FieldOptions = { - required?: boolean; - defaultValue?: any; - targetClass?: string; -}; /** * A Parse.Schema object is for handling schema data from Parse. *

All the schemas methods require MasterKey. @@ -58,7 +101,7 @@ type FieldOptions = { * * @alias Parse.Schema */ -declare class ParseSchema { +declare class ParseSchema { className: string; _fields: { [key: string]: any; @@ -93,14 +136,14 @@ declare class ParseSchema { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - save(): Promise; + save(): Promise; /** * Update a Schema on Parse * * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - update(): Promise; + update(): Promise; /** * Removing a Schema from Parse * Can only be used on Schema without objects @@ -144,7 +187,7 @@ declare class ParseSchema { * * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addField(name: string, type: string, options?: FieldOptions): this; + addField(name: string, type?: T, options?: FieldOptions): this; /** * Adding an Index to Create / Update a Schema * @@ -156,7 +199,7 @@ declare class ParseSchema { * schema.addIndex('index_name', { 'field': 1 }); * */ - addIndex(name: string, index: any): this; + addIndex(name: string, index: Index): this; /** * Adding String Field * @@ -164,7 +207,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addString(name: string, options: FieldOptions): this; + addString(name: AttrType, options?: FieldOptions): this; /** * Adding Number Field * @@ -172,7 +215,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addNumber(name: string, options: FieldOptions): this; + addNumber(name: AttrType, options?: FieldOptions): this; /** * Adding Boolean Field * @@ -180,7 +223,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addBoolean(name: string, options: FieldOptions): this; + addBoolean(name: AttrType, options?: FieldOptions): this; /** * Adding Bytes Field * @@ -188,7 +231,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addBytes(name: string, options: FieldOptions): this; + addBytes(name: AttrType, options?: FieldOptions): this; /** * Adding Date Field * @@ -196,7 +239,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addDate(name: string, options: FieldOptions): this; + addDate(name: AttrType, options?: FieldOptions): this; /** * Adding File Field * @@ -204,7 +247,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addFile(name: string, options: FieldOptions): this; + addFile(name: AttrType, options?: FieldOptions): this; /** * Adding GeoPoint Field * @@ -212,7 +255,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addGeoPoint(name: string, options: FieldOptions): this; + addGeoPoint(name: AttrType, options?: FieldOptions): this; /** * Adding Polygon Field * @@ -220,7 +263,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addPolygon(name: string, options: FieldOptions): this; + addPolygon(name: AttrType, options?: FieldOptions): this; /** * Adding Array Field * @@ -228,7 +271,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addArray(name: string, options: FieldOptions): this; + addArray(name: AttrType, options?: FieldOptions): this; /** * Adding Object Field * @@ -236,7 +279,7 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addObject(name: string, options: FieldOptions): this; + addObject(name: AttrType, options?: FieldOptions): this; /** * Adding Pointer Field * @@ -245,7 +288,11 @@ declare class ParseSchema { * @param {object} options See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Schema.html#addField addField} * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addPointer(name: string, targetClass: string, options?: FieldOptions): this; + addPointer( + name: AttrType, + targetClass: string, + options?: FieldOptions + ): this; /** * Adding Relation Field * @@ -253,7 +300,7 @@ declare class ParseSchema { * @param {string} targetClass Name of the target Pointer Class * @returns {Parse.Schema} Returns the schema, so you can chain this call. */ - addRelation(name: string, targetClass: string): this; + addRelation(name: AttrType, targetClass: string): this; /** * Deleting a Field to Update on a Schema * diff --git a/types/ParseSession.d.ts b/types/ParseSession.d.ts index 68be132bd..589189013 100644 --- a/types/ParseSession.d.ts +++ b/types/ParseSession.d.ts @@ -29,7 +29,7 @@ declare class ParseSession extends ParseObjec * object after it has been fetched. If there is no current user, the * promise will be rejected. */ - static current(options: FullOptions): Promise>; + static current(options?: FullOptions): Promise; /** * Determines whether the current session token is revocable. * This method is useful for migrating Express.js or Node.js web apps to diff --git a/types/ParseUser.d.ts b/types/ParseUser.d.ts index 91c87153b..6a1bb7a30 100644 --- a/types/ParseUser.d.ts +++ b/types/ParseUser.d.ts @@ -38,7 +38,7 @@ declare class ParseUser extends ParseObject; + _upgradeToRevocableSession(options?: RequestOptions): Promise; /** * Parse allows you to link your users with {@link https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication 3rd party authentication}, enabling * your users to sign up or log into your application using their existing identities. @@ -56,7 +56,7 @@ declare class ParseUser extends ParseObject extends ParseObject(): T | null; /** * Retrieves the currently logged in ParseUser from asynchronous Storage. * @@ -307,7 +307,7 @@ declare class ParseUser extends ParseObject; + static currentAsync(): Promise; /** * Signs up a new user with a username (or email) and password. * This will create a new Parse.User on the server, and also persist the @@ -322,12 +322,12 @@ declare class ParseUser extends ParseObject( username: string, password: string, attrs: Attributes, options?: FullOptions - ): Promise>; + ): Promise; /** * Logs in a user with a username (or email) and password. On success, this * saves the session to disk, so you can retrieve the currently logged in @@ -340,11 +340,11 @@ declare class ParseUser extends ParseObject( username: string, password: string, options?: FullOptions - ): Promise>; + ): Promise; /** * Logs in a user with a username (or email) and password, and authData. On success, this * saves the session to disk, so you can retrieve the currently logged in @@ -358,12 +358,12 @@ declare class ParseUser extends ParseObject( username: string, password: string, authData: AuthData, options?: FullOptions - ): Promise>; + ): Promise; /** * Logs in a user with an objectId. On success, this saves the session * to disk, so you can retrieve the currently logged in user using @@ -374,7 +374,7 @@ declare class ParseUser extends ParseObject>; + static loginAs(userId: string): Promise; /** * Logs in a user with a session token. On success, this saves the session * to disk, so you can retrieve the currently logged in user using @@ -387,7 +387,7 @@ declare class ParseUser extends ParseObject>; + static become(sessionToken: string, options?: RequestOptions): Promise; /** * Retrieves a user with a session token. * @@ -397,7 +397,7 @@ declare class ParseUser extends ParseObject>; + static me(sessionToken: string, options?: RequestOptions): Promise; /** * Logs in a user with a session token. On success, this saves the session * to disk, so you can retrieve the currently logged in user using @@ -408,7 +408,7 @@ declare class ParseUser extends ParseObject>; + static hydrate(userJSON: Attributes): Promise; /** * Static version of {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith} * @@ -419,13 +419,13 @@ declare class ParseUser extends ParseObject( + provider: string | AuthProvider, options: { authData?: AuthData; }, saveOpts?: FullOptions - ): Promise; + ): Promise; /** * Logs out the currently logged in user session. This will remove the * session from disk, log out of linked services, and future calls to @@ -478,11 +478,11 @@ declare class ParseUser extends ParseObject( username: string, password: string, options?: RequestOptions - ): Promise>; + ): Promise; /** * Allow someone to define a custom User class without className * being rewritten to _User. The default behavior is to rewrite diff --git a/types/Push.d.ts b/types/Push.d.ts index 24bf5214c..0c20bab33 100644 --- a/types/Push.d.ts +++ b/types/Push.d.ts @@ -7,6 +7,8 @@ export type PushData = { push_time?: Date | string; expiration_time?: Date | string; expiration_interval?: number; + data?: any; + channels?: string[]; }; /** * Contains functions to deal with Push in Parse. diff --git a/types/tests.ts b/types/tests.ts index 591a28edc..38e5a3fe1 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -3,14 +3,14 @@ import ParseNode from 'parse/node'; import ParseRN from 'parse/react-native'; class GameScore extends Parse.Object { - constructor(options?: any) { - super('GameScore', options); + constructor() { + super('GameScore'); } } class Game extends Parse.Object { - constructor(options?: any) { - super('Game', options); + constructor() { + super('Game'); } } @@ -51,11 +51,9 @@ async function test_object() { level: '10', difficult: 15, }); - - const score = gameScore.get('score'); - const playerName = gameScore.get('playerName'); - const cheatMode = gameScore.get('cheatMode'); - + gameScore.get('score'); + gameScore.get('playerName'); + gameScore.get('cheatMode'); gameScore.increment('score'); gameScore.addUnique('skills', 'flying'); gameScore.addUnique('skills', 'kungfu'); @@ -64,8 +62,8 @@ async function test_object() { gameScore.remove('skills', 'flying'); gameScore.removeAll('skills', ['kungFu']); game.set('gameScore', gameScore); - - const gameCopy = Game.fromJSON(JSON.parse(JSON.stringify(game)), true); + // $ExpectType ParseObject + Game.fromJSON(JSON.parse(JSON.stringify(game)), true); const object = new Parse.Object('TestObject'); object.equals(gameScore); @@ -73,12 +71,11 @@ async function test_object() { } function test_errors() { - try { - throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'sdfds'); - } catch (error) { - // $ExpectType any - error.code; - } + const error = new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'sdfds'); + // $ExpectType number + error.code; + // $ExpectType string + error.message; } async function test_query() { @@ -145,7 +142,9 @@ async function test_query() { query.equalTo('score', gameScore); query.exists('score'); query.include('score'); + query.include('score', 'team'); query.include(['score.team']); + query.include('*'); query.includeAll(); query.sortByTextScore(); // Find objects that match the aggregation pipeline @@ -337,12 +336,10 @@ function test_file_tags_and_metadata() { file.addTag('labes', 'one'); file.setMetadata({ contentType: 'plain/text', contentLength: 579 }); file.addMetadata('author', 'John Doe'); - - const tags = file.tags(); - const ownerId = tags['ownerId']; - - const metadata = file.metadata(); - const contentType = metadata['contentType']; + // $ExpectType Record + file.tags(); + // $ExpectType Record + file.metadata(); } async function test_analytics() { @@ -877,9 +874,10 @@ async function test_local_datastore() { await Parse.Object.unPinAllWithName(name, [obj]); await Parse.Object.unPinAllObjects(); await Parse.Object.unPinAllObjectsWithName(name); - - const flag = Parse.isLocalDatastoreEnabled(); - const LDS = await Parse.dumpLocalDatastore(); + // $ExpectType boolean + Parse.isLocalDatastoreEnabled(); + // $ExpectType any + await Parse.dumpLocalDatastore(); const query = new Parse.Query('TestObject'); query.fromPin(); @@ -1097,14 +1095,14 @@ function testObject() { // $ExpectType ParseObject<{ example: string; }> new Parse.Object('TestObject', { example: 'hello' }, { ignoreValidation: true }); - // // $ExpectError fix this - // new Parse.Object<{ example: string }>('TestObject'); + // $ExpectType ParseObject<{ example: string; }> + new Parse.Object<{ example: string }>('TestObject'); // $ExpectType ParseObject<{ example: number; }> new Parse.Object<{ example: number }>('TestObject', { example: 100 }); - // // $ExpectError fix this - // new Parse.Object<{ example: boolean }>('TestObject', { example: 'hello' }); + // $ExpectError + new Parse.Object<{ example: boolean }>('TestObject', { example: 'hello' }); } function testStaticMethods() { @@ -1507,6 +1505,9 @@ function testObject() { // $ExpectType ParseObject await objTyped.save({}); + // $ExpectType ParseObject + await objTyped.save(); + // $ExpectType ParseObject await objTypedOptional.save({ example: undefined }); @@ -1521,6 +1522,12 @@ function testObject() { // $ExpectType ParseObject await objTypedOptional.destroyEventually({}); + + // $ExpectType ParseObject + await objTypedOptional.saveEventually(); + + // $ExpectType ParseObject + await objTypedOptional.destroyEventually(); } function testSet( @@ -1534,7 +1541,7 @@ function testObject() { // $ExpectType ParseObject objUntyped.set({ propA: undefined }); - // $ExpectType ParseObject + // $ExpectError objTyped.set({ example: false }); // $ExpectType ParseObject @@ -1552,8 +1559,8 @@ function testObject() { // $ExpectError objTyped.set({ other: 'something' }); - // // $ExpectError fix this - // objTyped.set('example', 100); + // $ExpectError + objTyped.set('example', 100); // $ExpectError objTyped.set('other', 100); @@ -1562,10 +1569,10 @@ function testObject() { objTyped.set({ example: undefined }); // $ExpectType ParseObject - objTyped.set({}); + objTyped.set({}); // Should this error? - // // $ExpectError fix this - // objTyped.set('example', undefined); + // $ExpectType ParseObject + objTyped.set('example', undefined); // Should this error? // $ExpectType ParseObject objTypedOptional.set({ example: undefined }); @@ -1661,7 +1668,7 @@ function testObject() { objTyped.unset('other'); } - function testValidate(obj: Parse.Object<{}>) { + function testValidate(obj: Parse.Object) { // Note: The attributes being validated don't necessarily have to match the current object's attributes // $ExpectType ParseError | boolean @@ -1715,8 +1722,8 @@ function testInstallation() { // $ExpectType ParseInstallation<{ example: number; }> new Parse.Installation({ example: 100 }); - // // $ExpectError fix this - // new Parse.Installation<{ example: number }>(); + // $ExpectType ParseInstallation<{ example: number; }> + new Parse.Installation<{ example: number }>(); // $ExpectType ParseInstallation<{ example: number; }> new Parse.Installation<{ example: number }>({ example: 100 }); @@ -1763,6 +1770,10 @@ function testQuery() { // $ExpectType ParseQuery query.addAscending(['attribute1', 'attribute2', 'updatedAt']); + + // $ExpectType ParseQuery + query.addAscending('attribute1', 'attribute2', 'updatedAt'); + // $ExpectError query.addAscending(['attribute1', 'unexistenProp']); @@ -1904,10 +1915,19 @@ function testQuery() { // $ExpectType ParseQuery query.include(['attribute1', 'attribute2']); // $ExpectType ParseQuery + query.include('attribute1', 'attribute2'); + // $ExpectType ParseQuery query.include('attribute3.someProp'); // $ExpectError query.include(['attribute1', 'nonexistentProp']); + // $ExpectType ParseQuery + query.exclude('attribute1', 'attribute2'); + // $ExpectType ParseQuery + query.exclude(['attribute1', 'attribute2']); + // $ExpectError + query.exclude('attribute1', 'nonexistentProp'); + // $ExpectType ParseQuery query.lessThan('attribute2', 1000); // $ExpectError @@ -1965,6 +1985,8 @@ function testQuery() { // $ExpectType ParseQuery query.select('attribute1', 'attribute2'); + // $ExpectType ParseQuery + query.select(['attribute1', 'attribute2']); // $ExpectError query.select('attribute1', 'nonexistentProp'); @@ -1973,6 +1995,13 @@ function testQuery() { // $ExpectError query.startsWith('nonexistentProp', 'prefix string'); + // $ExpectType ParseQuery + query.watch('attribute1', 'attribute2'); + // $ExpectType ParseQuery + query.watch(['attribute1', 'attribute2']); + // $ExpectError + query.watch('attribute1', 'nonexistentProp'); + // $ExpectType ParseQuery query.withCount(true); @@ -2050,20 +2079,39 @@ function testRole() { } } -// $ExpectType ParseSession -new Parse.Session(); +function testSession() { + async function testConstructor() { + // $ExpectType ParseSession + const session = new Parse.Session(); + + // $ExpectType ParseSession<{ example: number; }> + new Parse.Session({ example: 100 }); -// $ExpectType ParseSession<{ example: number; }> -new Parse.Session({ example: 100 }); + // $ExpectType ParseSession<{ example: number; }> + new Parse.Session<{ example: number }>(); -// // $ExpectError fix this -// new Parse.Session<{ example: number }>(); + // $ExpectType ParseSession<{ example: number; }> + new Parse.Session<{ example: number }>({ example: 100 }); -// $ExpectType ParseSession<{ example: number; }> -new Parse.Session<{ example: number }>({ example: 100 }); + // $ExpectError + new Parse.Session<{ example: number }>({ example: 'hello' }); -// $ExpectError -new Parse.Session<{ example: number }>({ example: 'hello' }); + // $ExpectType boolean + Parse.Session.isCurrentSessionRevocable(); + + // $ExpectType string[] + Parse.Session.readOnlyAttributes(); + + // $ExpectType string + session.getSessionToken(); + + // $ExpectType ParseSession + await Parse.Session.current(); + + // $ExpectType ParseSession<{ example: string; }> + await Parse.Session.current>(); + } +} function testUser() { function testConstructor() { @@ -2073,8 +2121,8 @@ function testUser() { // $ExpectType ParseUser<{ example: number; }> new Parse.User({ example: 100 }); - // // $ExpectError fix this - // new Parse.User<{ example: number }>(); + // $ExpectType ParseUser<{ example: number; }> + new Parse.User<{ example: number }>(); // $ExpectType ParseUser<{ example: number; }> new Parse.User<{ example: number }>({ example: 100 }); @@ -2082,6 +2130,48 @@ function testUser() { // $ExpectError new Parse.User<{ example: number }>({ example: 'hello' }); } + + async function testStatic() { + const user = new Parse.User<{ field: 'hello' }>(); + + // $ExpectType ParseUser<{ field: "hello"; }> | null + Parse.User.current>(); + + // $ExpectType ParseUser<{ field: "hello"; }> | null + await Parse.User.currentAsync>(); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.signUp>('username', 'password', {}); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.become>('session-token'); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.logIn>('username', 'password'); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.logInWith>('provider', {}); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.logInWithAdditionalAuth>( + 'username', + 'password', + {} + ); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.loginAs>(user.id!); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.verifyPassword>('username', 'password'); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.hydrate>(user); + + // $ExpectType ParseUser<{ field: "hello"; }> + await Parse.User.me>('session-token'); + } + async function testAuthenticationProvider() { const authProvider: Parse.AuthProvider = { authenticate: () => {},