diff --git a/.gitignore b/.gitignore index 4efa43ee..1740ad6d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ node_modules/ *.log docs/ coverage/ -dist \ No newline at end of file +dist +yarn.lock +package-lock.json +pnpm-lock.yaml \ No newline at end of file diff --git a/src/database.ts b/src/database.ts index c5cf7a5d..2a301479 100644 --- a/src/database.ts +++ b/src/database.ts @@ -7,6 +7,7 @@ import Schema from './schema'; import SchemaType from './schematype'; import WarehouseError from './error'; import { logger } from 'hexo-log'; +import type { AddSchemaTypeOptions, NodeJSLikeCallback } from './types'; const log = logger(); const pkg = require('../package.json'); @@ -23,7 +24,7 @@ if (typeof writev === 'function') { }; } -async function exportAsync(database: Database, path: string) { +async function exportAsync(database: Database, path: string): Promise { const handle = await open(path, 'w'); try { @@ -79,7 +80,7 @@ interface DatabaseOptions { class Database { options: DatabaseOptions; - _models: any; + _models: Record>; Model: typeof Model; /** @@ -103,7 +104,7 @@ class Database { this._models = {}; - class _Model extends Model {} + class _Model extends Model {} this.Model = _Model; @@ -117,7 +118,7 @@ class Database { * @param {Schema|object} [schema] * @return {Model} */ - model(name: string, schema?: any) { + model(name: string, schema?: Schema | Record): Model { if (this._models[name]) { return this._models[name]; } @@ -133,7 +134,7 @@ class Database { * @param {function} [callback] * @return {Promise} */ - load(callback?) { + load(callback?: NodeJSLikeCallback): Bluebird { const { path, onUpgrade, onDowngrade, version: newVersion } = this.options; if (!path) throw new WarehouseError('options.path is required'); @@ -173,14 +174,14 @@ class Database { * @param {function} [callback] * @return {Promise} */ - save(callback?) { + save(callback?: NodeJSLikeCallback): Bluebird { const { path } = this.options; if (!path) throw new WarehouseError('options.path is required'); return Bluebird.resolve(exportAsync(this, path)).asCallback(callback); } - toJSON() { + toJSON(): { meta: { version: number, warehouse: string }, models: Record> } { const models = Object.keys(this._models) .reduce((obj, key) => { const value = this._models[key]; diff --git a/src/document.ts b/src/document.ts index 2c23b2e5..fcb5bbb3 100644 --- a/src/document.ts +++ b/src/document.ts @@ -1,17 +1,21 @@ import rfdc from 'rfdc'; +import type Model from './model'; +import type Schema from './schema'; +import type { NodeJSLikeCallback } from './types'; const cloneDeep = rfdc(); -abstract class Document { - abstract _model; - _id!: any; - abstract _schema; +abstract class Document { + abstract _model: Model; + _id!: string | number | undefined; + abstract _schema: Schema; + [key : string]: any; /** * Document constructor. * * @param {object} data */ - constructor(data) { + constructor(data?: T) { if (data) { Object.assign(this, data); } @@ -23,7 +27,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - save(callback) { + save(callback?: NodeJSLikeCallback): Promise { return this._model.save(this, callback); } @@ -34,7 +38,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - update(data, callback) { + update(data: object, callback?: NodeJSLikeCallback): Promise { return this._model.updateById(this._id, data, callback); } @@ -45,7 +49,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - replace(data, callback) { + replace(data: T | Document, callback?: NodeJSLikeCallback): Promise { return this._model.replaceById(this._id, data, callback); } @@ -55,7 +59,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - remove(callback) { + remove(callback?: NodeJSLikeCallback): Promise { return this._model.removeById(this._id, callback); } @@ -64,9 +68,9 @@ abstract class Document { * * @return {object} */ - toObject() { + toObject(): T { const keys = Object.keys(this); - const obj = {}; + const obj: Partial = {}; for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; @@ -75,7 +79,7 @@ abstract class Document { obj[key] = isGetter(this, key) ? this[key] : cloneDeep(this[key]); } - return obj; + return obj as T; } /** @@ -83,7 +87,7 @@ abstract class Document { * * @return {String} */ - toString() { + toString(): string { return JSON.stringify(this); } @@ -93,13 +97,13 @@ abstract class Document { * @param {String|Object} expr * @return {Document} */ - populate(expr) { + populate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Document { const stack = this._schema._parsePopulate(expr); return this._model._populate(this, stack); } } -function isGetter(obj, key) { +function isGetter(obj: any, key: PropertyKey): any { return Object.getOwnPropertyDescriptor(obj, key).get; } diff --git a/src/lib/jsonstream/index.ts b/src/lib/jsonstream/index.ts index e028660b..9a5dbf2f 100644 --- a/src/lib/jsonstream/index.ts +++ b/src/lib/jsonstream/index.ts @@ -7,7 +7,7 @@ import Parser from 'jsonparse'; * @param {*} y * @returns {boolean} */ -const check = (x, y) => { +const check = (x, y): boolean => { if (typeof x === 'string') { return y === x; } @@ -27,7 +27,7 @@ const check = (x, y) => { return false; }; -export function parse(path, map = null) { +export function parse(path: string | any[], map = null) { let header, footer; const parser = new Parser(); diff --git a/src/model.ts b/src/model.ts index ea3e4ffa..32a6429d 100644 --- a/src/model.ts +++ b/src/model.ts @@ -10,26 +10,28 @@ import * as Types from './types/index'; import WarehouseError from './error'; import PopulationError from './error/population'; import Mutex from './mutex'; +import type Database from './database'; +import type { AddSchemaTypeOptions, NodeJSLikeCallback, Options, PopulateResult } from './types'; -class Model extends EventEmitter { +class Model extends EventEmitter { _mutex = new Mutex(); - data: Record = {}; - schema; + data: Record = {}; + schema: Schema; length = 0; Document; Query; - _database; + _database: Database; /** * Model constructor. * * @param {string} name Model name - * @param {Schema|object} [schema] Schema + * @param {Schema|object} [schema_] Schema */ - constructor(public name: string, schema_) { + constructor(public name: string, schema_: Schema | Record) { super(); - let schema; + let schema: Schema; // Define schema if (schema_ instanceof Schema) { @@ -47,10 +49,10 @@ class Model extends EventEmitter { this.schema = schema; - class _Document extends Document { - _model!: Model; + class _Document extends Document { + _model!: Model; _schema!: Schema; - constructor(data) { + constructor(data: T) { super(data); // Apply getters @@ -63,8 +65,8 @@ class Model extends EventEmitter { _Document.prototype._model = this; _Document.prototype._schema = schema; - class _Query extends Query { - _model!: Model; + class _Query extends Query { + _model!: Model; _schema!: Schema; } @@ -86,7 +88,7 @@ class Model extends EventEmitter { * @param {object} data * @return {Document} */ - new(data) { + new(data?: T): Document { return new this.Document(data); } @@ -98,7 +100,7 @@ class Model extends EventEmitter { * @param {boolean} [options.lean=false] Returns a plain JavaScript object * @return {Document|object} */ - findById(id, options_?) { + findById(id: PropertyKey, options_?: Options): Document | T { const raw = this.data[id]; if (!raw) return; @@ -116,7 +118,7 @@ class Model extends EventEmitter { * @param {*} id * @return {boolean} */ - has(id) { + has(id: PropertyKey): boolean { return Boolean(this.data[id]); } @@ -143,11 +145,11 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _insertOne(data_) { + _insertOne(data_: Document | T): Promise { const schema = this.schema; // Apply getters - const data = data_ instanceof this.Document ? data_ : this.new(data_); + const data = (data_ instanceof this.Document ? data_ : this.new(data_ as T)) as Document; const id = data._id; // Check ID @@ -161,7 +163,7 @@ class Model extends EventEmitter { // Apply setters const result = data.toObject(); - schema._applySetters(result); + schema._applySetters(result as object); // Pre-hooks return execHooks(schema, 'pre', 'save', data).then(data => { @@ -181,7 +183,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - insertOne(data, callback?) { + insertOne(data: Document | T, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._insertOne(data)).asCallback(callback); } @@ -192,9 +194,9 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - insert(data, callback) { + insert(data: Document | T | Document[] | T[], callback?: NodeJSLikeCallback): Promise { if (Array.isArray(data)) { - return Promise.mapSeries(data, item => this.insertOne(item)).asCallback(callback); + return Promise.mapSeries | T, any>(data, item => this.insertOne(item)).asCallback(callback); } return this.insertOne(data, callback); @@ -207,8 +209,8 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - save(data, callback) { - const id = data._id; + save(data: Document | T, callback?: NodeJSLikeCallback): Promise { + const id = (data as any)._id; if (!id) return this.insertOne(data, callback); @@ -229,7 +231,7 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _updateWithStack(id, stack): Promise { + _updateWithStack(id: string | number, stack: ((data: any) => void)[]): Promise { const schema = this.schema; const data = this.data[id]; @@ -251,7 +253,7 @@ class Model extends EventEmitter { // Apply setters result = doc.toObject(); - schema._applySetters(result); + schema._applySetters(result as object); // Pre-hooks return execHooks(schema, 'pre', 'save', doc).then(data => { @@ -271,9 +273,9 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - updateById(id, update, callback?) { + updateById(id: string | number, update: object, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => { - const stack = this.schema._parseUpdate(update); + const stack = this.schema._parseUpdate(update as object); return this._updateWithStack(id, stack); }).asCallback(callback); } @@ -286,8 +288,8 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - update(query, data, callback?) { - return this.find(query).update(data, callback); + update(query: object, data: object, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).update(data, callback); } /** @@ -298,21 +300,21 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _replaceById(id, data_) { + _replaceById(id: string | number, data_: Document | T): Promise { const schema = this.schema; if (!this.has(id)) { return Promise.reject(new WarehouseError('ID `' + id + '` does not exist', WarehouseError.ID_NOT_EXIST)); } - data_._id = id; + (data_ as any)._id = id; // Apply getters - const data = data_ instanceof this.Document ? data_ : this.new(data_); + const data = (data_ instanceof this.Document ? data_ : this.new(data_ as T)) as Document; // Apply setters const result = data.toObject(); - schema._applySetters(result); + schema._applySetters(result as object); // Pre-hooks return execHooks(schema, 'pre', 'save', data).then(data => { @@ -332,7 +334,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - replaceById(id, data, callback?) { + replaceById(id: string | number, data: Document | T, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._replaceById(id, data)).asCallback(callback); } @@ -344,19 +346,18 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - replace(query, data, callback?) { - return this.find(query).replace(data, callback); + replace(query: object, data, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).replace(data, callback); } /** * Finds a document by its identifier and remove it. * * @param {*} id - * @param {function} [callback] * @return {Promise} * @private */ - _removeById(id) { + _removeById(id: string | number): Promise { const schema = this.schema; const data = this.data[id]; @@ -383,7 +384,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - removeById(id, callback) { + removeById(id: string | number, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._removeById(id)).asCallback(callback); } @@ -391,17 +392,17 @@ class Model extends EventEmitter { * Removes matching documents. * * @param {object} query - * @param {object} [callback] + * @param {function} [callback] * @return {Promise} */ - remove(query, callback) { - return this.find(query).remove(callback); + remove(query: object, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).remove(callback); } /** * Deletes a model. */ - destroy() { + destroy(): void { this._database._models[this.name] = null; } @@ -410,7 +411,7 @@ class Model extends EventEmitter { * * @return {number} */ - count() { + count(): number { return this.length; } @@ -420,7 +421,7 @@ class Model extends EventEmitter { * @param {function} iterator * @param {object} [options] See {@link Model#findById}. */ - forEach(iterator, options?) { + forEach(iterator: (value: any, index: number) => void, options?: Options): void { const keys = Object.keys(this.data); let num = 0; @@ -436,7 +437,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Array} */ - toArray(options?) { + toArray(options?: Options): any[] { const result = new Array(this.length); this.forEach((item, i) => { @@ -456,14 +457,16 @@ class Model extends EventEmitter { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Query|Array} */ - find(query, options: { limit?: number; skip?: number; lean?: boolean; } = {}) { + find(query: object): Query; + find(query: object, options: Options): Query | T[]; + find(query: object, options: Options = {}): Query | T[] { const filter = this.schema._execQuery(query); const keys = Object.keys(this.data); const len = keys.length; let limit = options.limit || this.length; let skip = options.skip; const data = this.data; - const arr = []; + const arr: (T | Document)[] = []; for (let i = 0; limit && i < len; i++) { const key = keys[i]; @@ -491,11 +494,13 @@ class Model extends EventEmitter { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Document|Object} */ - findOne(query, options_ : { skip?: number; lean?: boolean; } = {}) { + findOne(query: object): Document; + findOne(query: object, options_ : Options): Document | T; + findOne(query: object, options_ : Options = {}): Document | T { const options = Object.assign(options_, { limit: 1 }); const result = this.find(query, options); - return options.lean ? result[0] : result.data[0]; + return options.lean ? (result as any[])[0] : (result as Query).toArray()[0]; } /** @@ -505,7 +510,7 @@ class Model extends EventEmitter { * @param {String|Number} [order] * @return {Query} */ - sort(orderby, order) { + sort(orderby: string | object, order?: string | number): Query { const sort = parseArgs(orderby, order); const fn = this.schema._execSort(sort); @@ -520,7 +525,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - eq(i_, options?) { + eq(i_: number, options?: Options): Document | Record { let index = i_ < 0 ? this.length + i_ : i_; const data = this.data; const keys = Object.keys(data); @@ -545,7 +550,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - first(options) { + first(options?: Options): Document | Record { return this.eq(0, options); } @@ -555,7 +560,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - last(options) { + last(options?: Options): Document | Record { return this.eq(-1, options); } @@ -566,7 +571,7 @@ class Model extends EventEmitter { * @param {Number} [end] * @return {Query} */ - slice(start_: number, end_?: number) { + slice(start_?: number, end_?: number): Query { const total = this.length; let start = start_ | 0; @@ -605,7 +610,7 @@ class Model extends EventEmitter { * @param {Number} i * @return {Query} */ - limit(i) { + limit(i: number): Query { return this.slice(0, i); } @@ -615,7 +620,7 @@ class Model extends EventEmitter { * @param {Number} i * @return {Query} */ - skip(i) { + skip(i: number): Query { return this.slice(i); } @@ -624,7 +629,7 @@ class Model extends EventEmitter { * * @return {Query} */ - reverse() { + reverse(): Query { return new this.Query(this.toArray().reverse()); } @@ -633,7 +638,7 @@ class Model extends EventEmitter { * * @return {Query} */ - shuffle() { + shuffle(): Query { return new this.Query(shuffle(this.toArray())); } @@ -644,7 +649,7 @@ class Model extends EventEmitter { * @param {Object} [options] * @return {Array} */ - map(iterator, options) { + map(iterator: (value: any, index: number) => T, options?: Options): T[] { const result = new Array(this.length); const keys = Object.keys(this.data); const len = keys.length; @@ -668,10 +673,10 @@ class Model extends EventEmitter { * @param {*} [initial] By default, the initial value is the first document. * @return {*} */ - reduce(iterator, initial) { + reduce(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const arr = this.toArray(); const len = this.length; - let i, result; + let i: number, result: any; if (initial === undefined) { i = 1; @@ -696,7 +701,7 @@ class Model extends EventEmitter { * @param {*} [initial] By default, the initial value is the last document. * @return {*} */ - reduceRight(iterator, initial) { + reduceRight(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const arr = this.toArray(); const len = this.length; let i, result; @@ -724,10 +729,10 @@ class Model extends EventEmitter { * @param {Object} [options] * @return {Query} */ - filter(iterator, options) { + filter(iterator: (value: any, index: number) => any, options?: Options): Query { const arr = []; - this.forEach((item, i) => { + this.forEach((item: any, i: number) => { if (iterator(item, i)) arr.push(item); }, options); @@ -741,7 +746,7 @@ class Model extends EventEmitter { * @param {Function} iterator * @return {Boolean} */ - every(iterator) { + every(iterator: (value: any, index: number) => any): boolean { const keys = Object.keys(this.data); const len = keys.length; let num = 0; @@ -766,7 +771,7 @@ class Model extends EventEmitter { * @param {Function} iterator * @return {Boolean} */ - some(iterator) { + some(iterator: (value: any, index: number) => any): boolean { const keys = Object.keys(this.data); const len = keys.length; let num = 0; @@ -793,9 +798,9 @@ class Model extends EventEmitter { * @return {Function} * @private */ - _populateGetter(data, model, options) { + _populateGetter(data: string | number, model: Model, options: unknown) { let hasCache = false; - let cache; + let cache: Record | Document; return () => { if (!hasCache) { @@ -816,10 +821,10 @@ class Model extends EventEmitter { * @return {Function} * @private */ - _populateGetterArray(data, model, options) { + _populateGetterArray(data: any[], model: Model, options: Options): () => any[] | Query { const Query = model.Query; let hasCache = false; - let cache; + let cache: any[] | Query; return () => { if (!hasCache) { @@ -830,7 +835,7 @@ class Model extends EventEmitter { } if (options.match) { - cache = new Query(arr).find(options.match, options); + cache = (new Query(arr) as Query).find(options.match, options); } else if (options.skip) { if (options.limit) { arr = arr.slice(options.skip, options.skip + options.limit); @@ -864,7 +869,7 @@ class Model extends EventEmitter { * @return {Object} * @private */ - _populate(data, stack) { + _populate(data: Document, stack: PopulateResult[]): Document { const models = this._database._models; for (let i = 0, len = stack.length; i < len; i++) { @@ -894,7 +899,7 @@ class Model extends EventEmitter { * @param {String|Object} path * @return {Query} */ - populate(path) { + populate(path: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Query { if (!path) throw new TypeError('path is required'); const stack = this.schema._parsePopulate(path); @@ -913,14 +918,14 @@ class Model extends EventEmitter { * @param {Array} arr * @private */ - _import(arr) { + _import(arr: any[]) { const len = arr.length; const data = this.data; const schema = this.schema; for (let i = 0; i < len; i++) { const item = arr[i]; - data[item._id] = schema._parseDatabase(item); + data[item._id] = schema._parseDatabase(item) as T; } this.length = len; @@ -932,11 +937,11 @@ class Model extends EventEmitter { * @return {String} * @private */ - _export() { + _export(): string { return JSON.stringify(this.toJSON()); } - toJSON() { + toJSON(): any[] { const result = new Array(this.length); const { data, schema } = this; const keys = Object.keys(data); @@ -945,20 +950,20 @@ class Model extends EventEmitter { for (let i = 0, num = 0; i < length; i++) { const raw = data[keys[i]]; if (raw) { - result[num++] = schema._exportDatabase(cloneDeep(raw)); + result[num++] = schema._exportDatabase(cloneDeep(raw) as object); } } return result; } - get: Model['findById']; - size: Model['count']; - each: Model['forEach']; - random: Model['shuffle']; + get: Model['findById']; + size: Model['count']; + each: Model['forEach']; + random: Model['shuffle']; } Model.prototype.get = Model.prototype.findById; -function execHooks(schema, type, event, data) { +function execHooks(schema: Schema, type: string, event: string, data: any): Promise { const hooks = schema.hooks[type][event] as ((data: any) => Promise | void)[]; if (!hooks.length) return Promise.resolve(data); diff --git a/src/mutex.ts b/src/mutex.ts index 6eaa0ab4..dec0dbea 100644 --- a/src/mutex.ts +++ b/src/mutex.ts @@ -6,7 +6,7 @@ class Mutex { this._queue = []; } - lock(fn: () => void) { + lock(fn: () => void): void { if (this._locked) { this._queue.push(fn); return; @@ -16,7 +16,7 @@ class Mutex { fn(); } - unlock() { + unlock(): void { if (!this._locked) return; const next = this._queue.shift(); diff --git a/src/query.ts b/src/query.ts index 0eb8fae4..d9445909 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,17 +1,23 @@ import Promise from 'bluebird'; import { parseArgs, shuffle } from './util'; +import type Model from './model'; +import type Schema from './schema'; +import type Document from './document'; +import type { NodeJSLikeCallback, Options } from './types'; -abstract class Query { +abstract class Query { + data: Document[]; length: number; - abstract _model; - abstract _schema; + abstract _model: Model; + abstract _schema: Schema; /** * Query constructor. * * @param {Array} data */ - constructor(private data: any[]) { + constructor(data: Document[]) { + this.data = data; this.length = data.length; } @@ -42,7 +48,7 @@ abstract class Query { * * @return {Array} */ - toArray(): any[] { + toArray(): Document[] { return this.data; } @@ -53,7 +59,7 @@ abstract class Query { * @param {Number} i * @return {Document|Object} */ - eq(i: number) { + eq(i: number): Document { const index = i < 0 ? this.length + i : i; return this.data[index]; } @@ -63,7 +69,7 @@ abstract class Query { * * @return {Document|Object} */ - first() { + first(): Document { return this.eq(0); } @@ -72,7 +78,7 @@ abstract class Query { * * @return {Document|Object} */ - last() { + last(): Document { return this.eq(-1); } @@ -83,7 +89,7 @@ abstract class Query { * @param {Number} [end] * @return {Query} */ - slice(start: number, end?: number): Query { + slice(start: number, end?: number): Query { return Reflect.construct(this.constructor, [this.data.slice(start, end)]); } @@ -93,7 +99,7 @@ abstract class Query { * @param {Number} i * @return {Query} */ - limit(i: number): Query { + limit(i: number): Query { return this.slice(0, i); } @@ -103,7 +109,7 @@ abstract class Query { * @param {Number} i * @return {Query} */ - skip(i: number): Query { + skip(i: number): Query { return this.slice(i); } @@ -112,7 +118,7 @@ abstract class Query { * * @return {Query} */ - reverse(): Query { + reverse(): Query { return Reflect.construct(this.constructor, [this.data.slice().reverse()]); } @@ -121,7 +127,7 @@ abstract class Query { * * @return {Query} */ - shuffle(): Query { + shuffle(): Query { return Reflect.construct(this.constructor, [shuffle(this.data)]); } @@ -135,7 +141,9 @@ abstract class Query { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Query|Array} */ - find(query: any, options: { limit?: number; skip?: number; lean?: boolean; } = {}): any[] | Query { + find(query: object): Query; + find(query: object, options: Options): T[] | Query; + find(query: object, options: Options = {}): T[] | Query { const filter = this._schema._execQuery(query); const { data, length } = this; const { lean = false } = options; @@ -167,7 +175,9 @@ abstract class Query { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Document|Object} */ - findOne(query: any, options: { skip?: number; lean?: boolean; } = {}): any { + findOne(query: object): Document; + findOne(query: object, options): Document | T; + findOne(query: object, options: Options = {}): Document | T { const _options = Object.assign(options, { limit: 1 }); const result = this.find(query, _options); @@ -192,7 +202,7 @@ abstract class Query { * @param {String|Number} [order] * @return {Query} */ - sort(orderby, order): Query { + sort(orderby: string | object, order?: string | number | object): Query { const sort = parseArgs(orderby, order); const fn = this._schema._execSort(sort); @@ -224,9 +234,9 @@ abstract class Query { * @param {*} [initial] By default, the initial value is the first document. * @return {*} */ - reduce(iterator, initial?) { + reduce(iterator: (pre: any, cur: any, index: number) => R, initial?: R): R { const { data, length } = this; - let result, i; + let result, i: number; if (initial === undefined) { i = 1; @@ -251,7 +261,7 @@ abstract class Query { * @param {*} [initial] By default, the initial value is the last document. * @return {*} */ - reduceRight(iterator, initial?) { + reduceRight(iterator: (pre: any, cur: any, index: number) => R, initial?: R): R { const { data, length } = this; let result, i; @@ -277,7 +287,7 @@ abstract class Query { * @param {Function} iterator * @return {Query} */ - filter(iterator: (item: any, index: number) => boolean): Query { + filter(iterator: (item: any, index: number) => boolean): Query { const { data, length } = this; const arr = []; @@ -330,7 +340,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - update(data: any, callback?: (err?: any) => void): Promise { + update(data: any, callback?: NodeJSLikeCallback): Promise { const model = this._model; const stack = this._schema._parseUpdate(data); @@ -344,7 +354,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - replace(data: any, callback?: (err?: any) => void): Promise { + replace(data: any, callback?: NodeJSLikeCallback): Promise { const model = this._model; return Promise.map(this.data, item => model.replaceById(item._id, data)).asCallback(callback); @@ -356,7 +366,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - remove(callback) { + remove(callback?: NodeJSLikeCallback): Promise { const model = this._model; return Promise.mapSeries(this.data, item => model.removeById(item._id)).asCallback(callback); @@ -368,7 +378,7 @@ abstract class Query { * @param {String|Object} expr * @return {Query} */ - populate(expr: any): Query { + populate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Query { const stack = this._schema._parsePopulate(expr); const { data, length } = this; const model = this._model; @@ -380,9 +390,9 @@ abstract class Query { return this; } - size: Query['count']; - each: Query['forEach']; - random: Query['shuffle']; + size: Query['count']; + each: Query['forEach']; + random: Query['shuffle']; } Query.prototype.size = Query.prototype.count; diff --git a/src/schema.ts b/src/schema.ts index f9f81590..933a3598 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -5,18 +5,21 @@ import { getProp, setProp, delProp } from './util'; import PopulationError from './error/population'; import SchemaTypeVirtual from './types/virtual'; import { isPlainObject } from 'is-plain-object'; +import type { AddSchemaTypeLoopOptions, AddSchemaTypeOptions, PopulateResult, SchemaTypeOptions } from './types'; /** * @callback queryFilterCallback * @param {*} data * @return {boolean} */ +type queryFilterCallback = (data: unknown) => boolean; /** * @callback queryCallback * @param {*} data * @return {void} */ +type queryCallback = (data: unknown) => void; /** * @callback queryParseCallback @@ -24,18 +27,13 @@ import { isPlainObject } from 'is-plain-object'; * @param {*} b * @returns {*} */ - -/** - * @typedef PopulateResult - * @property {string} path - * @property {*} model - */ +type queryParseCallback = (a: unknown, b: unknown) => number; const builtinTypes = new Set(['String', 'Number', 'Boolean', 'Array', 'Object', 'Date', 'Buffer']); -const getSchemaType = (name, options) => { - const Type = options.type || options; - const typeName = Type.name; +const getSchemaType = (name: string, options: { type: SchemaTypeOptions; [key: string]: any } | SchemaTypeOptions) => { + const Type = (options as any).type || options; + const typeName: string = Type.name; if (builtinTypes.has(typeName)) { return new Types[typeName](name, options); @@ -44,13 +42,13 @@ const getSchemaType = (name, options) => { return new Type(name, options); }; -const checkHookType = type => { +const checkHookType = (type: string) => { if (type !== 'save' && type !== 'remove') { throw new TypeError('Hook type must be `save` or `remove`!'); } }; -const hookWrapper = fn => { +const hookWrapper = (fn: (...args: any[]) => void): (...args: any[]) => Promise => { if (fn.length > 1) { return Promise.promisify(fn); } @@ -61,11 +59,11 @@ const hookWrapper = fn => { /** * @param {Function[]} stack */ -const execSortStack = stack => { +const execSortStack = (stack: ((a: unknown, b: unknown) => number)[]) => { const len = stack.length; - return (a, b) => { - let result; + return (a: any, b: any) => { + let result: number; for (let i = 0; i < len; i++) { result = stack[i](a, b); @@ -76,32 +74,32 @@ const execSortStack = stack => { }; }; -const sortStack = (path_, key, sort) => { +const sortStack = (path_: SchemaType, key: string, sort: string | number) => { const path = path_ || new SchemaType(key); const descending = sort === 'desc' || sort === -1; - return (a, b) => { + return (a: any, b: any) => { const result = path.compare(getProp(a, key), getProp(b, key)); return descending && result ? result * -1 : result; }; }; class UpdateParser { - static updateStackNormal(key, update) { - return data => { setProp(data, key, update); }; + static updateStackNormal(key: string, update: any) { + return (data: any) => { setProp(data, key, update); }; } - static updateStackOperator(path_, ukey, key, update) { + static updateStackOperator(path_: SchemaType, ukey: string | number, key: string, update: any) { const path = path_ || new SchemaType(key); - return data => { + return (data: any) => { const result = path[ukey](getProp(data, key), update, data); setProp(data, key, result); }; } // eslint-disable-next-line no-useless-constructor - constructor(private paths) {} + constructor(private paths: Record>) { } /** * Parses updating expressions and returns a stack. @@ -110,11 +108,11 @@ class UpdateParser { * @param {queryCallback[]} [stack] * @private */ - parseUpdate(updates, prefix = '', stack = []) { + parseUpdate(updates: object, prefix = '', stack: queryCallback[] = []): queryCallback[] { const { paths } = this; const { updateStackOperator } = UpdateParser; const keys = Object.keys(updates); - let path, prefixNoDot; + let path: SchemaType, prefixNoDot: string; if (prefix) { prefixNoDot = prefix.substring(0, prefix.length - 1); @@ -158,7 +156,7 @@ class UpdateParser { */ class QueryParser { // eslint-disable-next-line no-useless-constructor - constructor(private paths) {} + constructor(private paths: Record>) { } /** * @@ -166,10 +164,10 @@ class QueryParser { * @param {*} query * @return {queryFilterCallback} */ - queryStackNormal(name, query) { + queryStackNormal(name: string, query: unknown): queryFilterCallback { const path = this.paths[name] || new SchemaType(name); - return data => path.match(getProp(data, name), query, data); + return (data: unknown) => path.match(getProp(data, name), query, data); } /** @@ -179,7 +177,7 @@ class QueryParser { * @param {*} query * @return {queryFilterCallback} */ - queryStackOperator(qkey, name, query) { + queryStackOperator(qkey: string, name: string, query: any): queryFilterCallback { const path = this.paths[name] || new SchemaType(name); return data => path[qkey](getProp(data, name), query, data); @@ -191,7 +189,7 @@ class QueryParser { * @return {void} * @private */ - $and(arr, stack) { + $and(arr: any[], stack: queryFilterCallback[]): void { for (let i = 0, len = arr.length; i < len; i++) { stack.push(this.execQuery(arr[i])); } @@ -202,7 +200,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $or(query) { + $or(query: any[]): queryFilterCallback { const stack = this.parseQueryArray(query); const len = stack.length; @@ -220,7 +218,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $nor(query) { + $nor(query: any[]): queryFilterCallback { const stack = this.parseQueryArray(query); const len = stack.length; @@ -238,7 +236,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $not(query) { + $not(query: any): queryFilterCallback { const stack = this.parseQuery(query); const len = stack.length; @@ -262,7 +260,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $where(fn) { + $where(fn: (...args: any[]) => boolean): queryFilterCallback { return data => Reflect.apply(fn, data, []); } @@ -273,7 +271,7 @@ class QueryParser { * @return {queryFilterCallback[]} * @private */ - parseQueryArray(arr) { + parseQueryArray(arr: any[]): queryFilterCallback[] { const stack = []; this.$and(arr, stack); return stack; @@ -288,7 +286,7 @@ class QueryParser { * @return {void} * @private */ - parseNormalQuery(queries, prefix, stack = []) { + parseNormalQuery(queries: object, prefix: string, stack: queryFilterCallback[] = []): void { const keys = Object.keys(queries); for (let i = 0, len = keys.length; i < len; i++) { @@ -316,10 +314,10 @@ class QueryParser { * @return {queryFilterCallback[]} * @private */ - parseQuery(queries) { + parseQuery(queries: any): queryFilterCallback[] { /** @type {queryFilterCallback[]} */ - const stack = []; + const stack: queryFilterCallback[] = []; const keys = Object.keys(queries); for (let i = 0, len = keys.length; i < len; i++) { @@ -366,7 +364,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - execQuery(query) { + execQuery(query: object): queryFilterCallback { const stack = this.parseQuery(query); const len = stack.length; @@ -380,19 +378,34 @@ class QueryParser { } } + class Schema { paths: Record> = {}; - statics: Record = {}; - methods: Record = {}; - hooks; - stacks; + statics: Record any> = {}; + methods: Record any> = {}; + hooks: { + pre: { + save: ((...args: any[]) => Promise)[] + remove: ((...args: any[]) => Promise)[] + }; + post: { + save: ((...args: any[]) => Promise)[] + remove: ((...args: any[]) => Promise)[] + }; + }; + stacks: { + getter: ((data: object) => void)[]; + setter: ((data: object) => void)[]; + import: ((data: object) => void)[]; + export: ((data: object) => void)[]; + }; /** * Schema constructor. * * @param {Object} [schema] */ - constructor(schema?) { + constructor(schema?: Record) { this.hooks = { pre: { save: [], @@ -422,7 +435,7 @@ class Schema { * @param {Object} schema * @param {String} prefix */ - add(schema: Record, prefix = ''): void { + add(schema: Record, prefix = ''): void { const keys = Object.keys(schema); const len = keys.length; @@ -444,8 +457,8 @@ class Schema { * @return {SchemaType | undefined} */ path(name: string): SchemaType; - path(name: string, obj: SchemaType | ((...args: any[]) => any) | { type: any; } | Record | any[]): void; - path(name: string, obj?: SchemaType | ((...args: any[]) => any) | { type: any; } | Record | any[]): SchemaType | void { + path(name: string, obj: AddSchemaTypeOptions): void; + path(name: string, obj?: AddSchemaTypeOptions): SchemaType | void { if (obj == null) { return this.paths[name]; } @@ -458,7 +471,7 @@ class Schema { } else { switch (typeof obj) { case 'function': - type = getSchemaType(name, {type: obj}); + type = getSchemaType(name, { type: obj }); break; case 'object': @@ -467,7 +480,7 @@ class Schema { child: obj.length ? getSchemaType(name, obj[0]) : new SchemaType(name) }); } else if (obj.type) { - type = getSchemaType(name, obj); + type = getSchemaType(name, obj as { type: SchemaTypeOptions; }); } else { type = new Types.Object(); nested = Object.keys(obj).length > 0; @@ -483,7 +496,7 @@ class Schema { this.paths[name] = type; this._updateStack(name, type); - if (nested) this.add(obj, `${name}.`); + if (nested) this.add(obj as AddSchemaTypeLoopOptions, `${name}.`); } /** @@ -493,7 +506,7 @@ class Schema { * @param {SchemaType} type * @private */ - _updateStack(name: string, type: SchemaType) { + _updateStack(name: string, type: SchemaType): void { const { stacks } = this; stacks.getter.push(data => { @@ -559,7 +572,7 @@ class Schema { * @param {String} type Hook type. One of `save` or `remove`. * @param {Function} fn */ - pre(type, fn) { + pre(type: 'save' | 'remove', fn: (...args: any[]) => void): void { checkHookType(type); if (typeof fn !== 'function') throw new TypeError('Hook must be a function!'); @@ -572,7 +585,7 @@ class Schema { * @param {String} type Hook type. One of `save` or `remove`. * @param {Function} fn */ - post(type, fn) { + post(type: 'save' | 'remove', fn: (...args: any[]) => void): void { checkHookType(type); if (typeof fn !== 'function') throw new TypeError('Hook must be a function!'); @@ -585,7 +598,7 @@ class Schema { * @param {String} name * @param {Function} fn */ - method(name, fn) { + method(name: string, fn: (...args: any[]) => any) { if (!name) throw new TypeError('Method name is required!'); if (typeof fn !== 'function') { @@ -601,7 +614,7 @@ class Schema { * @param {String} name * @param {Function} fn */ - static(name: string, fn) { + static(name: string, fn: (...args: any[]) => any) { if (!name) throw new TypeError('Method name is required!'); if (typeof fn !== 'function') { @@ -618,7 +631,7 @@ class Schema { * @return {void} * @private */ - _applyGetters(data) { + _applyGetters(data: object): void { const stack = this.stacks.getter; for (let i = 0, len = stack.length; i < len; i++) { @@ -633,7 +646,7 @@ class Schema { * @return {void} * @private */ - _applySetters(data) { + _applySetters(data: object): void { const stack = this.stacks.setter; for (let i = 0, len = stack.length; i < len; i++) { @@ -648,7 +661,7 @@ class Schema { * @return {Object} * @private */ - _parseDatabase(data) { + _parseDatabase(data: object): object { const stack = this.stacks.import; for (let i = 0, len = stack.length; i < len; i++) { @@ -665,7 +678,7 @@ class Schema { * @return {Object} * @private */ - _exportDatabase(data) { + _exportDatabase(data: object): object { const stack = this.stacks.export; for (let i = 0, len = stack.length; i < len; i++) { @@ -682,7 +695,7 @@ class Schema { * @return {queryCallback[]} * @private */ - _parseUpdate(updates) { + _parseUpdate(updates: object): queryCallback[] { return new UpdateParser(this.paths).parseUpdate(updates); } @@ -693,7 +706,7 @@ class Schema { * @return {queryFilterCallback} * @private */ - _execQuery(query) { + _execQuery(query: object): queryFilterCallback { return new QueryParser(this.paths).execQuery(query); } @@ -707,7 +720,7 @@ class Schema { * @return {queryParseCallback[]} * @private */ - _parseSort(sorts, prefix = '', stack = []) { + _parseSort(sorts: object, prefix = '', stack: queryParseCallback[] = []): queryParseCallback[] { const { paths } = this; const keys = Object.keys(sorts); @@ -733,7 +746,7 @@ class Schema { * @return {queryParseCallback} * @private */ - _execSort(sorts) { + _execSort(sorts: object): queryParseCallback { const stack = this._parseSort(sorts); return execSortStack(stack); } @@ -746,7 +759,7 @@ class Schema { * @private */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - _parsePopulate(expr) { + _parsePopulate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): PopulateResult[] { const { paths } = this; const arr = []; diff --git a/src/schematype.ts b/src/schematype.ts index 22dea735..0ba0b6d2 100644 --- a/src/schematype.ts +++ b/src/schematype.ts @@ -56,7 +56,7 @@ class SchemaType { * @param {Boolean} [options.required=false] * @param {*} [options.default] */ - constructor(public name = '', options?: { required?: boolean; default?: (() => T) | T; }) { + constructor(public name: string = '', options?: { required?: boolean; default?: (() => T) | T; }) { this.options = Object.assign({ required: false }, options); @@ -64,7 +64,7 @@ class SchemaType { const default_ = this.options.default; if (typeof default_ === 'function') { - this.default = default_ as unknown as () => T; + this.default = default_ as () => T; } else { this.default = () => default_; } @@ -244,7 +244,7 @@ class SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value, query, data?) { + q$nin(value: unknown, query: unknown[], data?: unknown): boolean { return !query.includes(value); } @@ -256,7 +256,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$set(value, update, data?) { + u$set(value: unknown, update: T, data?: unknown): T { return update; } @@ -268,7 +268,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$unset(value, update, data?) { return update ? undefined : value; } + u$unset(value: T, update: boolean, data?: unknown): T | undefined { return update ? undefined : value; } /** * Renames a field. @@ -278,7 +278,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$rename(value, update, data): void { + u$rename(value: unknown, update: unknown, data: unknown): void { if (value !== undefined) setProp(data, update, value); return undefined; } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..21f6107f --- /dev/null +++ b/src/types.ts @@ -0,0 +1,32 @@ +import type SchemaType from './schematype'; + +export type NodeJSLikeCallback = (err: E, result?: R) => void + +export interface Options { + lean?: boolean; + skip?: number; + limit?: number; + [key: PropertyKey]: any; +} + +export type SchemaTypeOptions = typeof SchemaType | SchemaType | ((...args: any[]) => any) + +export type AddSchemaTypeSimpleOptions = SchemaTypeOptions | { type: SchemaTypeOptions; [key: string]: any }; + +export type AddSchemaTypeMixedOptions = AddSchemaTypeSimpleOptions | AddSchemaTypeSimpleOptions[]; + +export interface AddSchemaTypeLoopOptions { + [key: string]: AddSchemaTypeMixedOptions | AddSchemaTypeLoopOptions; +} + +export type AddSchemaTypeOptions = AddSchemaTypeMixedOptions | AddSchemaTypeLoopOptions; + +/** + * @typedef PopulateResult + * @property {string} path + * @property {*} model + */ +export type PopulateResult = { + path: string; + model: any; +}; diff --git a/src/types/array.ts b/src/types/array.ts index 3c51f36f..dd27c7f9 100644 --- a/src/types/array.ts +++ b/src/types/array.ts @@ -29,13 +29,15 @@ class SchemaTypeArray> extends SchemaType { /** * Casts an array and its child elements. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Array} */ - cast(value_?: unknown, data?: unknown): I[] | null | undefined { + cast(value_: Exclude, data?: unknown): I[]; + cast(value_?: unknown, data?: unknown): I[] | undefined; + cast(value_?: unknown, data?: unknown): I[] | undefined { value_ = super.cast(value_, data); - if (value_ == null) return value_ as null | undefined; + if (value_ == null) return value_ as undefined; const value = isArray(value_) ? value_ : value_ = [value_]; if (!value.length) return value; @@ -52,7 +54,7 @@ class SchemaTypeArray> extends SchemaType { /** * Validates an array and its child elements. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Array|Error} */ @@ -107,8 +109,10 @@ class SchemaTypeArray> extends SchemaType { * @param {Array} value * @return {Array} */ - parse(value?: unknown[]) { - if (!value) return value; + parse(value: unknown[]): I[]; + parse(): undefined; + parse(value?: unknown[]): I[] | undefined { + if (!value) return value as undefined; const len = value.length; if (!len) return []; @@ -117,7 +121,7 @@ class SchemaTypeArray> extends SchemaType { const child = this.child; for (let i = 0; i < len; i++) { - result[i] = child.parse(value[i]); + result[i] = child.parse(value[i]) as I; } return result; @@ -130,8 +134,10 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - value(value?: unknown[], data?: unknown): any[] { - if (!value) return value; + value(value: unknown[], data?: unknown): any[] + value(): undefined; + value(value?: unknown[], data?: unknown): any[] | undefined { + if (!value) return value as undefined; const len = value.length; if (!len) return []; @@ -211,7 +217,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value?: unknown[], query?: unknown[], data?: unknown): boolean { + q$nin(value?: T[], query?: T[], data?: unknown): boolean { if (!value) return true; for (let i = 0, len = query.length; i < len; i++) { @@ -229,7 +235,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$all(value?: unknown[], query?: unknown[], data?: unknown): boolean { + q$all(value?: T[], query?: T[], data?: unknown): boolean { if (!value) return false; for (let i = 0, len = query.length; i < len; i++) { @@ -268,7 +274,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$unshift(value?: unknown[], update?: unknown, data?: unknown): any[] { + u$unshift(value?: T[], update?: T | T[], data?: unknown): T[] { if (isArray(update)) { return value ? update.concat(value) : update; } @@ -289,7 +295,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$pull(value?: unknown[], update?: unknown, data?: unknown): any[] { + u$pull(value?: T[], update?: T | T[], data?: unknown): T[] { if (!value) return value; if (isArray(update)) { @@ -307,7 +313,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$shift(value?, update?, data?) { + u$shift(value?: T[], update?: number | boolean, data?: unknown): T[] { if (!value || !update) return value; if (update === true) { @@ -327,7 +333,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$pop(value?, update?, data?) { + u$pop(value?: T[], update?: number | boolean, data?: unknown): T[] { if (!value || !update) return value; const length = value.length; @@ -349,7 +355,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$addToSet(value?: any[], update?, data?) { + u$addToSet(value?: T[], update?: T | T[], data?: unknown): T[] { if (isArray(update)) { if (!value) return update; diff --git a/src/types/boolean.ts b/src/types/boolean.ts index 55330fde..1160dfe2 100644 --- a/src/types/boolean.ts +++ b/src/types/boolean.ts @@ -9,7 +9,7 @@ class SchemaTypeBoolean extends SchemaType { /** * Casts a boolean. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Boolean} */ @@ -24,7 +24,7 @@ class SchemaTypeBoolean extends SchemaType { /** * Validates a boolean. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Boolean|Error} */ diff --git a/src/types/buffer.ts b/src/types/buffer.ts index 73cc157e..f5927ff1 100644 --- a/src/types/buffer.ts +++ b/src/types/buffer.ts @@ -14,7 +14,7 @@ class SchemaTypeBuffer extends SchemaType { * @param {boolean|Function} [options.default] * @param {string} [options.encoding=hex] */ - constructor(name: string, options?) { + constructor(name: string, options?: Partial['options']> & { encoding?: BufferEncoding; }) { super(name, Object.assign({ encoding: 'hex' }, options)); @@ -23,14 +23,16 @@ class SchemaTypeBuffer extends SchemaType { /** * Casts data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Buffer} */ - cast(value_?: unknown, data?): Buffer | null | undefined { + cast(value_: WithImplicitCoercion | string>, data?: unknown): Buffer; + cast(value_?: unknown, data?: unknown): Buffer | undefined; + cast(value_?: unknown, data?: unknown): Buffer | undefined { const value = super.cast(value_, data); - if (value == null || Buffer.isBuffer(value)) return value as Buffer | null | undefined; + if (value == null || Buffer.isBuffer(value)) return value as Buffer | undefined; if (typeof value === 'string') return Buffer.from(value, this.options.encoding); if (Array.isArray(value)) return Buffer.from(value); } @@ -38,11 +40,11 @@ class SchemaTypeBuffer extends SchemaType { /** * Validates data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Buffer} */ - validate(value_: unknown, data?): Buffer { + validate(value_: unknown, data?: unknown): Buffer { const value = super.validate(value_, data); if (!Buffer.isBuffer(value)) { @@ -73,7 +75,9 @@ class SchemaTypeBuffer extends SchemaType { * @param {*} value * @return {Boolean} */ - parse(value?) { + parse(value: WithImplicitCoercion | string>): Buffer; + parse(value?: unknown): Buffer | null | undefined; + parse(value?: any): Buffer | null | undefined { return value ? Buffer.from(value, this.options.encoding) : value; } @@ -81,9 +85,9 @@ class SchemaTypeBuffer extends SchemaType { * Transforms data into number to compress the size of database files. * * @param {Buffer} value - * @return {Number} + * @return {String} */ - value(value?: Buffer) { + value(value?: Buffer): string { return Buffer.isBuffer(value) ? value.toString(this.options.encoding) : value; } diff --git a/src/types/cuid.ts b/src/types/cuid.ts index 49b057c6..476cfa0c 100644 --- a/src/types/cuid.ts +++ b/src/types/cuid.ts @@ -14,7 +14,7 @@ class SchemaTypeCUID extends SchemaType { * @param {String} value * @return {String} */ - cast(value?) { + cast(value?: string): string { if (value == null && this.options.required) { return cuid(); } @@ -28,7 +28,7 @@ class SchemaTypeCUID extends SchemaType { * @param {*} value * @return {String|Error} */ - validate(value?) { + validate(value?: string): string { if (value && (value[0] !== 'c' || value.length !== 25)) { throw new ValidationError(`\`${value}\` is not a valid CUID`); } diff --git a/src/types/date.ts b/src/types/date.ts index 40727b87..398d09e6 100644 --- a/src/types/date.ts +++ b/src/types/date.ts @@ -9,17 +9,15 @@ class SchemaTypeDate extends SchemaType { /** * Casts data. * - * @param {*} value + * @param {*} value_ * @return {Date | null | undefined} */ - cast(value_?): Date | null | undefined; - cast(value_: Date): Date; - cast(value_: null): Date | null; - cast(value_: undefined): Date | undefined; - cast(value_: unknown): Date | null | undefined { + cast(value_: Date | number | string): Date; + cast(value_?: unknown): Date | undefined; + cast(value_?: unknown): Date | undefined { const value = super.cast(value_, null); - if (value == null || value instanceof Date) return value as Date | null | undefined; + if (value == null || value instanceof Date) return value as Date | undefined; return new Date(value as any); } @@ -27,18 +25,18 @@ class SchemaTypeDate extends SchemaType { /** * Validates data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Date|Error} */ - validate(value_, data?) { + validate(value_: unknown, data?: unknown): Date { const value = super.validate(value_, data); if (value != null && (!(value instanceof Date) || isNaN(value.getTime()))) { throw new ValidationError(`\`${value}\` is not a valid date!`); } - return value; + return value as Date; } /** @@ -63,9 +61,9 @@ class SchemaTypeDate extends SchemaType { * @param {Date} b * @return {Number} */ - compare(a?, b?) { + compare(a?: Date, b?: Date): number { if (a) { - return b ? a - b : 1; + return b ? a.getTime() - b.getTime() : 1; } return b ? -1 : 0; @@ -77,7 +75,9 @@ class SchemaTypeDate extends SchemaType { * @param {*} value * @return {Date} */ - parse(value?) { + parse(value: string | number | Date): Date; + parse(): undefined; + parse(value?: string | number | Date): Date | undefined { if (value) return new Date(value); } @@ -87,8 +87,10 @@ class SchemaTypeDate extends SchemaType { * @param {Date} value * @return {String} */ - value(value?) { - return value ? value.toISOString() : value; + value(value: Date): string; + value(): undefined; + value(value?: Date): string | undefined { + return value ? value.toISOString() : value as undefined; } /** @@ -98,7 +100,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$day(value, query) { + q$day(value: Date | undefined, query: number): boolean { return value ? value.getDate() === query : false; } @@ -109,7 +111,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$month(value, query) { + q$month(value: Date | undefined, query: number): boolean { return value ? value.getMonth() === query : false; } @@ -120,7 +122,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$year(value, query) { + q$year(value: Date | undefined, query: number): boolean { return value ? value.getFullYear() === query : false; } @@ -131,7 +133,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} update * @return {Date} */ - u$inc(value, update) { + u$inc(value: Date | undefined, update: number): Date { if (value) return new Date(value.getTime() + update); } @@ -142,7 +144,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} update * @return {Date} */ - u$dec(value, update) { + u$dec(value: Date | undefined, update: number): Date { if (value) return new Date(value.getTime() - update); } } diff --git a/src/types/enum.ts b/src/types/enum.ts index 1a96d88c..42ee6c26 100644 --- a/src/types/enum.ts +++ b/src/types/enum.ts @@ -15,7 +15,7 @@ class SchemaTypeEnum extends SchemaType { * @param {Array} options.elements * @param {*} [options.default] */ - constructor(name, options) { + constructor(name: string, options?: Partial['options']> & { elements?: any[] }) { super(name, Object.assign({ elements: [] }, options)); @@ -24,11 +24,11 @@ class SchemaTypeEnum extends SchemaType { /** * Validates data. The value must be one of elements set in the options. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {*} */ - validate(value_, data?) { + validate(value_: unknown, data?: unknown) { const value = super.validate(value_, data); const elements = this.options.elements; diff --git a/src/types/integer.ts b/src/types/integer.ts index 97b74d5e..c5400212 100644 --- a/src/types/integer.ts +++ b/src/types/integer.ts @@ -9,11 +9,11 @@ class SchemaTypeInteger extends SchemaTypeNumber { /** * Casts a integer. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Number} */ - cast(value_?, data?): number { + cast(value_?: unknown, data?: unknown): number { const value = super.cast(value_, data); return parseInt(value as any, 10); @@ -22,11 +22,11 @@ class SchemaTypeInteger extends SchemaTypeNumber { /** * Validates an integer. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Number|Error} */ - validate(value_?, data?): number { + validate(value_?: unknown, data?: unknown): number { const value = super.validate(value_, data); if (!Number.isInteger(value)) { diff --git a/src/types/number.ts b/src/types/number.ts index 83dcbe2c..6b0a072d 100644 --- a/src/types/number.ts +++ b/src/types/number.ts @@ -13,10 +13,12 @@ class SchemaTypeNumber extends SchemaType { * @param {Object} data * @return {Number} */ - cast(value_?, data?): number | null | undefined { + cast(value_: Exclude, data?: unknown): number; + cast(value_?: unknown, data?: unknown): number | undefined; + cast(value_?: unknown, data?: unknown): number | undefined { const value = super.cast(value_, data); - if (value == null || typeof value === 'number') return value as number | null | undefined; + if (value == null || typeof value === 'number') return value as number | undefined; return +value; } @@ -28,14 +30,14 @@ class SchemaTypeNumber extends SchemaType { * @param {Object} data * @return {Number|Error} */ - validate(value_?, data?) { + validate(value_?: unknown, data?: unknown): number { const value = super.validate(value_, data); if (value !== undefined && (typeof value !== 'number' || isNaN(value))) { throw new ValidationError(`\`${value}\` is not a number!`); } - return value; + return value as number; } /** @@ -45,7 +47,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$inc(value, update) { + u$inc(value: number | undefined, update: number): number { return value ? value + update : update; } @@ -56,7 +58,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$dec(value, update) { + u$dec(value: number | undefined, update: number): number { return value ? value - update : -update; } @@ -67,7 +69,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$mul(value, update) { + u$mul(value: number | undefined, update: number): number { return value ? value * update : 0; } @@ -78,7 +80,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$div(value, update) { + u$div(value: number | undefined, update: number): number { return value ? value / update : 0; } @@ -89,7 +91,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$mod(value, update) { + u$mod(value: number | undefined, update: number): number { return value ? value % update : 0; } @@ -100,7 +102,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$max(value, update) { + u$max(value: number | undefined, update: number): number { return update > value ? update : value; } @@ -111,7 +113,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$min(value, update) { + u$min(value: number | undefined, update: number): number { return update < value ? update : value; } } diff --git a/src/types/object.ts b/src/types/object.ts index 840fa20c..7024288d 100644 --- a/src/types/object.ts +++ b/src/types/object.ts @@ -12,7 +12,7 @@ class SchemaTypeObject extends SchemaType> { * @param {Boolean} [options.required=false] * @param {Object|Function} [options.default={}] */ - constructor(name?, options?) { + constructor(name?: string, options?: Partial>['options']>) { super(name, Object.assign({ default: {} }, options)); } } diff --git a/src/types/string.ts b/src/types/string.ts index 589ee085..03d9be1f 100644 --- a/src/types/string.ts +++ b/src/types/string.ts @@ -9,32 +9,34 @@ class SchemaTypeString extends SchemaType { /** * Casts a string. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {String} */ - cast(value_?, data?) { + cast(value_: { toString(): string }, data?: unknown): string; + cast(value_?: unknown, data?: unknown): string | undefined; + cast(value_?: unknown, data?: unknown): string | undefined { const value = super.cast(value_, data); - if (value == null || typeof value === 'string') return value; + if (value == null || typeof value === 'string') return value as string | undefined; if (typeof value.toString === 'function') return value.toString(); } /** * Validates a string. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {String|Error} */ - validate(value_?, data?) { + validate(value_?: unknown, data?: unknown): string { const value = super.validate(value_, data); if (value !== undefined && typeof value !== 'string') { throw new ValidationError(`\`${value}\` is not a string!`); } - return value; + return value as string; } /** @@ -45,13 +47,13 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - match(value, query, data?) { + match(value: string | undefined, query: string | RegExp | undefined, data?: unknown): boolean { if (!value || !query) { return value === query; } - if (typeof query.test === 'function') { - return query.test(value); + if (typeof(query as any).test === 'function') { + return (query as RegExp).test(value); } return value === query; @@ -65,7 +67,7 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$in(value, query, data?) { + q$in(value: string | undefined, query: string[] | RegExp[], data?: unknown): boolean { for (let i = 0, len = query.length; i < len; i++) { if (this.match(value, query[i], data)) return true; } @@ -81,7 +83,7 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value, query, data?) { + q$nin(value: string | undefined, query: string[] | RegExp[], data?: unknown): boolean { return !this.q$in(value, query, data); } @@ -92,7 +94,7 @@ class SchemaTypeString extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$length(value, query) { + q$length(value: string | undefined, query: number): boolean { return (value ? value.length : 0) === query; } } diff --git a/src/types/virtual.ts b/src/types/virtual.ts index aa333a5a..383907b3 100644 --- a/src/types/virtual.ts +++ b/src/types/virtual.ts @@ -14,7 +14,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Function} fn * @chainable */ - get(fn) { + get(fn: () => any): SchemaTypeVirtual { if (typeof fn !== 'function') { throw new TypeError('Getter must be a function!'); } @@ -30,7 +30,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Function} fn * @chainable */ - set(fn) { + set(fn: (value: any) => void): SchemaTypeVirtual { if (typeof fn !== 'function') { throw new TypeError('Setter must be a function!'); } @@ -47,7 +47,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Object} data * @return {*} */ - cast(value, data) { + cast(value: unknown, data: any): void { if (typeof this.getter !== 'function') return; const getter = this.getter; @@ -70,7 +70,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {*} value * @param {Object} data */ - validate(value, data) { + validate(value: any, data: any): void { if (typeof this.setter === 'function') { this.setter.call(data, value); } diff --git a/src/util.ts b/src/util.ts index 62cef092..b7ab5d57 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,8 +1,8 @@ -function extractPropKey(key) { +function extractPropKey(key: string): string[] { return key.split('.'); } -function _parseArgs(args) { +function _parseArgs(args: string) { if (typeof args !== 'string') return args; const arr = args.split(' '); @@ -173,12 +173,12 @@ export function reverse(arr) { return arr; } -export function parseArgs(orderby, order?) { +export function parseArgs(orderby: string | object, order?: string | number | object) { let result; if (order) { result = {}; - result[orderby] = order; + result[orderby as string] = order; } else if (typeof orderby === 'string') { result = _parseArgs(orderby); } else { diff --git a/test/scripts/document.ts b/test/scripts/document.ts index abac13a4..565215ff 100644 --- a/test/scripts/document.ts +++ b/test/scripts/document.ts @@ -2,18 +2,30 @@ import chai from 'chai'; const should = chai.should(); // eslint-disable-line import Database from '../../dist/database'; import Document from '../../dist/document'; +import type Model from '../../dist/model'; + +interface UserType { + name?: string; + age?: number; + comments?: string; +} + +interface CommentType { + content?: string; + author?: string; +} describe('Document', () => { const db = new Database(); const Schema = Database.Schema; - const User = db.model('User', { + const User: Model = db.model('User', { name: String, age: Number, comments: [{type: Schema.Types.CUID, ref: 'Comment'}] }); - const Comment = db.model('Comment', { + const Comment: Model = db.model('Comment', { content: String, author: {type: Schema.Types.CUID, ref: 'User'} }); @@ -39,7 +51,7 @@ describe('Document', () => { const doc = User.new({}); return doc.save().then(item => { - User.findById(doc._id).should.exist; + User.findById(doc._id as string | number).should.exist; return User.removeById(item._id); }); }); @@ -115,5 +127,5 @@ describe('Document', () => { user.populate('comments').comments.toArray().should.eql(comments); return comments; - }).map(comment => Comment.removeById(comment._id))); + }).map(comment => Comment.removeById(comment._id))); }); diff --git a/test/scripts/model.ts b/test/scripts/model.ts index 88589338..c5b20116 100644 --- a/test/scripts/model.ts +++ b/test/scripts/model.ts @@ -9,6 +9,26 @@ import Promise from 'bluebird'; import sinon from 'sinon'; import cuid from 'cuid'; import Database from '../../dist/database'; +import type Query from '../../dist/query'; +import type Document from '../../dist/document'; +import type Model from '../../dist/model'; + +interface UserType { + name?: { + first: string; + last: string; + } + email?: string; + age?: number; + posts?: string[]; +} + +interface PostType { + title?: string; + content?: string; + user_id?: string; + created?: Date; +} describe('Model', () => { @@ -38,8 +58,8 @@ describe('Model', () => { created: Date }); - const User = db.model('User', userSchema); - const Post = db.model('Post', postSchema); + const User: Model = db.model('User', userSchema); + const Post: Model = db.model('Post', postSchema); it('new()', () => { const user = User.new({ @@ -48,7 +68,7 @@ describe('Model', () => { age: 20 }); - user._id.should.exist; + user._id!.should.exist; user.name.first.should.eql('John'); user.name.last.should.eql('Doe'); user.name.full.should.eql('John Doe'); @@ -98,16 +118,17 @@ describe('Model', () => { const doc = User.new(); delete doc._id; - return User.insert(doc).should.eventually.be.rejected; + return (User.insert(doc) as any).should.eventually.be.rejected; }); it('insert() - already existed', () => { let user; - return User.insert({}).then(data => { + // @ts-ignore + return (User.insert({}).then(data => { user = data; return User.insert(data); - }).finally(() => User.removeById(user._id)).should.eventually.be.rejected; + }).finally(() => User.removeById(user._id)) as any).should.eventually.be.rejected; }); it('insert() - hook', () => { @@ -150,7 +171,7 @@ describe('Model', () => { ]).then(data => { data.length = 2; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('insert() - sync problem', () => { const db = new Database(); @@ -301,7 +322,7 @@ describe('Model', () => { return data; }).then(data => User.removeById(data._id))); - it('updateById() - id not exist', () => User.updateById('foo', {}).should.eventually.be.rejected); + it('updateById() - id not exist', () => (User.updateById('foo', {}) as any).should.eventually.be.rejected); it('updateById() - hook', () => { const db = new Database(); @@ -341,7 +362,7 @@ describe('Model', () => { updated[0].email.should.eql('A'); updated[1].email.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('replaceById()', () => { function validate(data) { @@ -371,7 +392,7 @@ describe('Model', () => { }).then(data => User.removeById(data._id)); }); - it('replaceById() - id not exist', () => User.replaceById('foo', {}).should.eventually.be.rejected); + it('replaceById() - id not exist', () => (User.replaceById('foo', {}) as any).should.eventually.be.rejected); it('replaceById() - pre-hook', () => { const db = new Database(); @@ -411,7 +432,7 @@ describe('Model', () => { updated[0].email.should.eql('A'); updated[1].email.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('removeById()', () => { const listener = sinon.spy(data => { @@ -430,7 +451,7 @@ describe('Model', () => { }); }); - it('removeById() - id not exist', () => User.removeById('foo', {}).should.eventually.be.rejected); + it('removeById() - id not exist', () => (User.removeById('foo', () => {}) as any).should.eventually.be.rejected); it('removeById() - hook', () => { const db = new Database(); @@ -489,13 +510,13 @@ describe('Model', () => { count.should.eql(data.length); return data; - }).map(item => Post.removeById(item._id)); + }).map(item => Post.removeById(item._id)); }); it('toArray()', () => Post.insert(Array(10).fill({})).then(data => { Post.toArray().should.eql(data); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('find()', () => User.insert([ {age: 10}, @@ -504,10 +525,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: 20}); + const query = User.find({age: 20}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - blank', () => User.insert([ {age: 10}, @@ -516,10 +537,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}); + const query = User.find({}) as Query; query.data.should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - operator', () => User.insert([ {age: 10}, @@ -527,10 +548,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: {$gt: 20}}); + const query = User.find({age: {$gt: 20}}) as Query; query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - limit', () => User.insert([ {age: 10}, @@ -538,10 +559,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: {$gte: 20}}, {limit: 2}); + const query = User.find({age: {$gte: 20}}, {limit: 2}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - skip', () => User.insert([ {age: 10}, @@ -549,15 +570,15 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - let query = User.find({age: {$gte: 20}}, {skip: 1}); + let query = User.find({age: {$gte: 20}}, {skip: 1}) as Query; query.data.should.eql(data.slice(2)); // with limit - query = User.find({age: {$gte: 20}}, {limit: 1, skip: 1}); + query = User.find({age: {$gte: 20}}, {limit: 1, skip: 1}) as Query; query.data.should.eql(data.slice(2, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - lean', () => User.insert([ {age: 10}, @@ -568,7 +589,7 @@ describe('Model', () => { const query = User.find({age: {$gt: 20}}, {lean: true}); query.should.be.a('array'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $and', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -582,10 +603,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql([data[1]]); + (query as Query).toArray().should.eql([data[1]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $or', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -599,10 +620,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql(data.slice(1)); + (query as Query).toArray().should.eql(data.slice(1)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $nor', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -616,10 +637,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql([data[0]]); + (query as Query).toArray().should.eql([data[0]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $not', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -630,10 +651,10 @@ describe('Model', () => { $not: {'name.last': 'Doe'} }); - query.toArray().should.eql(data.slice(2)); + (query as Query).toArray().should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $where', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -646,10 +667,10 @@ describe('Model', () => { } }); - query.toArray().should.eql(data.slice(0, 2)); + (query as Query).toArray().should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne()', () => User.insert([ {age: 10}, @@ -659,7 +680,7 @@ describe('Model', () => { ]).then(data => { User.findOne({age: {$gt: 20}}).should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne() - lean', () => User.insert([ {age: 10}, @@ -667,9 +688,9 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - User.findOne({age: {$gt: 20}}, {lean: true})._id.should.eql(data[2]._id); + (User.findOne({age: {$gt: 20}}, {lean: true}) as Document)._id!.should.eql(data[2]._id); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort()', () => User.insert([ {age: 15}, @@ -681,7 +702,7 @@ describe('Model', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - descending', () => User.insert([ {age: 15}, @@ -693,7 +714,7 @@ describe('Model', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - multi', () => User.insert([ {age: 15, email: 'A'}, @@ -707,7 +728,7 @@ describe('Model', () => { query.data[2].should.eql(data[3]); query.data[3].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq()', () => Post.insert(Array(5).fill({})).then(data => { for (let i = 0, len = data.length; i < len; i++) { @@ -715,7 +736,7 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('eq() - negative index', () => Post.insert(Array(5).fill({})).then(data => { for (let i = 1, len = data.length; i <= len; i++) { @@ -723,7 +744,7 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('eq() - no data', () => { (typeof Post.eq(1)).should.eql('undefined'); @@ -733,68 +754,68 @@ describe('Model', () => { Post.first().should.eql(data[0]); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('last()', () => Post.insert(Array(5).fill({})).then(data => { Post.last().should.eql(data[data.length - 1]); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - no arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice().data.should.eql(data); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - one argument', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(2).data.should.eql(data.slice(2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - one negative argument', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-2).data.should.eql(data.slice(-2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - two arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(2, 4).data.should.eql(data.slice(2, 4)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - start + negative end index', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(1, -1).data.should.eql(data.slice(1, -1)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - two negative arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-3, -1).data.should.eql(data.slice(-3, -1)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - start > end', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-1, -3).data.should.eql(data.slice(-1, -3)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - index overflow', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(1, 100).data.should.eql(data.slice(1, 100)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - index overflow 2', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(100, 200).data.should.eql(data.slice(100, 200)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('limit()', () => Post.insert(Array(5).fill({})).then(data => { Post.limit(2).data.should.eql(data.slice(0, 2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('skip()', () => Post.insert(Array(5).fill({})).then(data => { Post.skip(2).data.should.eql(data.slice(2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reverse()', () => Post.insert(Array(5).fill({})).then(data => { const query = Post.reverse(); @@ -804,13 +825,13 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('shuffle()', () => Post.insert(Array(5).fill({})).then(data => { const query = Post.shuffle(); sortBy(query.data, '_id').should.eql(sortBy(data, '_id')); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('map()', () => Post.insert(Array(5).fill({})).then(data => { let num = 0; @@ -825,75 +846,75 @@ describe('Model', () => { d1.should.eql(d2); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduce()', () => Post.insert([ - {email: 'A'}, - {email: 'B'}, - {email: 'C'} + {title: 'A'}, + {title: 'B'}, + {title: 'C'} ]).then(data => { let num = 1; const sum = Post.reduce((sum, item, i) => { i.should.eql(num++); - return {email: sum.email + item.email}; + return {title: sum.title + item.title}; }); - sum.email.should.eql('ABC'); + sum.title.should.eql('ABC'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduce() - with initial', () => Post.insert([ - {email: 'A'}, - {email: 'B'}, - {email: 'C'} + {title: 'A'}, + {title: 'B'}, + {title: 'C'} ]).then(data => { let num = 0; const sum = Post.reduce((sum, item, i) => { i.should.eql(num++); - return sum + item.email; + return sum + item.title; }, '_'); sum.should.eql('_ABC'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduceRight()', () => Post.insert([ - {email: 'A'}, - {email: 'B'}, - {email: 'C'} + {title: 'A'}, + {title: 'B'}, + {title: 'C'} ]).then(data => { let num = 1; const sum = Post.reduceRight((sum, item, i) => { i.should.eql(num--); - return {email: sum.email + item.email}; + return {title: sum.title + item.title}; }); - sum.email.should.eql('CBA'); + sum.title.should.eql('CBA'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduceRight() - with initial', () => Post.insert([ - {email: 'A'}, - {email: 'B'}, - {email: 'C'} + {title: 'A'}, + {title: 'B'}, + {title: 'C'} ]).then(data => { let num = 2; const sum = Post.reduceRight((sum, item, i) => { i.should.eql(num--); - return sum + item.email; + return sum + item.title; }, '_'); sum.should.eql('_CBA'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('filter()', () => User.insert([ {age: 10}, @@ -911,7 +932,7 @@ describe('Model', () => { query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('every()', () => User.insert([ {age: 10}, @@ -929,7 +950,7 @@ describe('Model', () => { User.every((data, i) => data.age > 10).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('some()', () => User.insert([ {age: 10}, @@ -947,10 +968,11 @@ describe('Model', () => { }).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('populate() - error', () => { try { + // @ts-ignore Post.populate(); } catch (err) { err.message.should.eql('path is required'); @@ -1230,7 +1252,7 @@ describe('Model', () => { const Test = db.model('Test', schema); - Test.add({name: 'foo'}).then(data => { + (Test as any).add({name: 'foo'}).then(data => { data.name.should.eql('foo'); }); @@ -1299,7 +1321,7 @@ describe('Model', () => { it('_export() - should not save undefined value', () => { // @ts-ignore - class CacheType extends SchemaType { + class CacheType extends SchemaType { value() {} } diff --git a/test/scripts/query.ts b/test/scripts/query.ts index 81192205..af5adaa1 100644 --- a/test/scripts/query.ts +++ b/test/scripts/query.ts @@ -5,19 +5,33 @@ const { sortBy } = lodash; import Promise from 'bluebird'; import Document from '../../dist/document'; import Database from '../../dist/database'; +import type Query from '../../dist/query'; +import type Model from '../../dist/model'; + +interface UserType { + name?: string; + age?: number; + comments?: string; +} + +interface LoopType { + age: { + age: number; + } +} describe('Query', () => { const db = new Database(); const Schema = Database.Schema; - const User = db.model('User', { + const User: Model = db.model('User', { name: String, age: Number, comments: [{type: Schema.Types.CUID, ref: 'Comment'}] }); - const Loop = db.model('Loop', { + const Loop: Model = db.model('Loop', { age: { age: Number } @@ -31,7 +45,7 @@ describe('Query', () => { it('count()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).count().should.eql(data.length); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('forEach()', () => User.insert(Array(5).fill({})).then(data => { let count = 0; @@ -42,12 +56,12 @@ describe('Query', () => { }); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('toArray()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).toArray().should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq()', () => User.insert(Array(5).fill({})).then(data => { const query = User.find({}); @@ -57,7 +71,7 @@ describe('Query', () => { } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq() - negative index', () => User.insert(Array(5).fill({})).then(data => { const query = User.find({}); @@ -67,42 +81,42 @@ describe('Query', () => { } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('first()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).first().should.eql(data[0]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('last()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).last().should.eql(data[data.length - 1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('slice()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).slice(2, 4).data.should.eql(data.slice(2, 4)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('limit()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).limit(2).data.should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('skip()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).skip(2).data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reverse()', () => User.insert(Array(5).fill({})).then(data => { User.find({}).reverse().data.should.eql(data.reverse()); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('shuffle()', () => User.insert(Array(5).fill({})).then(data => { sortBy(User.find({}).shuffle().data, '_id').should.eql(sortBy(data, '_id')); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find()', () => User.insert([ {age: 10}, @@ -120,7 +134,7 @@ describe('Query', () => { query.data[i].should.to.be.an.instanceof(Document); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - blank', () => User.insert([ {age: 10}, @@ -132,7 +146,7 @@ describe('Query', () => { const query = User.find({}).find({}); query.data.should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - operator', () => User.insert([ {age: 10}, @@ -143,7 +157,7 @@ describe('Query', () => { const query = User.find({}).find({age: {$gt: 20}}); query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - limit', () => User.insert([ {age: 10}, @@ -151,10 +165,10 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: {$gte: 20}}, {limit: 2}); + const query = User.find({}).find({age: {$gte: 20}}, {limit: 2}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - skip', () => User.insert([ {age: 10}, @@ -162,15 +176,15 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - let query = User.find({}).find({age: {$gte: 20}}, {skip: 1}); + let query = User.find({}).find({age: {$gte: 20}}, {skip: 1}) as Query; query.data.should.eql(data.slice(2)); // with limit - query = User.find({}).find({age: {$gte: 20}}, {limit: 1, skip: 1}); + query = User.find({}).find({age: {$gte: 20}}, {limit: 1, skip: 1}) as Query; query.data.should.eql(data.slice(2, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - lean', () => User.insert([ {age: 10}, @@ -178,14 +192,14 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: {$gt: 20}}, {lean: true}); + const query = User.find({}).find({age: {$gt: 20}}, {lean: true}) as Query; query.should.be.a('array'); const { length } = query; for (let i = 0; i < length; i++) { query[i].should.to.not.be.an.instanceof(Document); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $and', () => User.insert([ {name: 'John', age: 20}, @@ -202,7 +216,7 @@ describe('Query', () => { query.toArray().should.eql([data[1]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $or', () => User.insert([ {name: 'John', age: 20}, @@ -219,7 +233,7 @@ describe('Query', () => { query.toArray().should.eql(data.slice(1)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $nor', () => User.insert([ {name: 'John', age: 20}, @@ -236,7 +250,7 @@ describe('Query', () => { query.toArray().should.eql([data[0]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $not', () => User.insert([ {name: 'John', age: 20}, @@ -250,7 +264,7 @@ describe('Query', () => { query.toArray().should.eql([data[2]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $where', () => User.insert([ {name: 'John', age: 20}, @@ -266,7 +280,7 @@ describe('Query', () => { query.toArray().should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - abnormal - 1', () => User.insert([ {name: 'John', age: 20}, @@ -282,7 +296,7 @@ describe('Query', () => { query.toArray().length.should.eql(0); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - abnormal - 2', () => User.insert([ {name: 'John', age: 20}, @@ -298,7 +312,7 @@ describe('Query', () => { query.toArray().should.eql([data[2]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne()', () => User.insert([ {age: 10}, @@ -310,7 +324,7 @@ describe('Query', () => { result.should.eql(data[2]); result.should.to.be.an.instanceof(Document); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne() - lean', () => User.insert([ {age: 10}, @@ -318,11 +332,11 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const result = User.find({}).findOne({age: {$gt: 20}}, {lean: true}); - result._id.should.eql(data[2]._id); + const result = User.find({}).findOne({age: {$gt: 20}}, {lean: true}) as Document; + result._id!.should.eql(data[2]._id); result.should.to.not.be.an.instanceof(Document); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort()', () => User.insert([ {age: 15}, @@ -334,7 +348,7 @@ describe('Query', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - object', () => Loop.insert([ {age: {age: 15}}, @@ -346,7 +360,7 @@ describe('Query', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => Loop.removeById(item._id))); + }).map(item => Loop.removeById(item._id))); it('sort() - descending', () => User.insert([ {age: 15}, @@ -358,7 +372,7 @@ describe('Query', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - multi', () => User.insert([ {age: 15, name: 'A'}, @@ -372,7 +386,7 @@ describe('Query', () => { query.data[2].should.eql(data[3]); query.data[3].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('map()', () => User.insert(Array(5).fill({})).then(data => { let num = 0; @@ -387,7 +401,7 @@ describe('Query', () => { d1.should.eql(d2); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduce()', () => User.insert([ {name: 'A'}, @@ -404,7 +418,7 @@ describe('Query', () => { sum.name.should.eql('ABC'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduce() - initial', () => User.insert([ {name: 'A'}, @@ -421,7 +435,7 @@ describe('Query', () => { sum.should.eql('_ABC'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduceRight()', () => User.insert([ {name: 'A'}, @@ -438,7 +452,7 @@ describe('Query', () => { sum.name.should.eql('CBA'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduceRight() - initial', () => User.insert([ {name: 'A'}, @@ -455,7 +469,7 @@ describe('Query', () => { sum.should.eql('_CBA'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('filter()', () => User.insert([ {age: 10}, @@ -473,7 +487,7 @@ describe('Query', () => { query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('every()', () => User.insert([ {age: 10}, @@ -491,7 +505,7 @@ describe('Query', () => { User.find({}).every((data, i) => data.age > 10).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('some()', () => User.insert([ {age: 10}, @@ -509,7 +523,7 @@ describe('Query', () => { }).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('update()', () => User.insert([ {age: 10}, @@ -523,7 +537,7 @@ describe('Query', () => { updated[0].name.should.eql('A'); updated[1].name.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('replace()', () => User.insert([ {age: 10}, @@ -537,7 +551,7 @@ describe('Query', () => { updated[0].name.should.eql('A'); updated[1].name.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('remove()', () => User.insert([ {age: 10}, @@ -549,7 +563,7 @@ describe('Query', () => { should.not.exist(User.findById(data[1]._id)); should.not.exist(User.findById(data[3]._id)); return [data[0], data[2], data[4]]; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('populate() - object', () => { let user, comment; diff --git a/test/scripts/schema.ts b/test/scripts/schema.ts index 2a4f9a70..dbe04a8f 100644 --- a/test/scripts/schema.ts +++ b/test/scripts/schema.ts @@ -100,9 +100,11 @@ describe('Schema', () => { schema.hooks.pre.remove.should.have.length(1); // incompatible type + // @ts-ignore (() => schema.pre('wtf', () => {})).should.to.throw(TypeError, 'Hook type must be `save` or `remove`!'); // hook is not a function + // @ts-ignore (() => schema.pre('save', {})).should.to.throw(TypeError, 'Hook must be a function!'); }); @@ -120,9 +122,11 @@ describe('Schema', () => { schema.hooks.post.remove.should.have.length(1); // incompatible type + // @ts-ignore (() => schema.post('wtf', () => {})).should.throw(TypeError, 'Hook type must be `save` or `remove`!'); // hook is not a function + // @ts-ignore (() => schema.post('save', {})).should.to.throw(TypeError, 'Hook must be a function!'); }); @@ -137,6 +141,7 @@ describe('Schema', () => { schema.method.should.to.throw(TypeError, 'Method name is required!'); // without function + // @ts-ignore (() => schema.method('wtf', {})).should.to.throw(TypeError, 'Instance method must be a function!'); }); @@ -151,6 +156,7 @@ describe('Schema', () => { schema.static.should.to.throw(TypeError, 'Method name is required!'); // without function + // @ts-ignore (() => schema.static('wtf', {})).should.to.throw(TypeError, 'Static method must be a function!'); }); }); diff --git a/test/scripts/schematype.ts b/test/scripts/schematype.ts index a49090e5..39abb55f 100644 --- a/test/scripts/schematype.ts +++ b/test/scripts/schematype.ts @@ -4,24 +4,24 @@ import ValidationError from '../../dist/error/validation'; import SchemaType from '../../dist/schematype'; describe('SchemaType', () => { - const type = new SchemaType('test'); + const type = new SchemaType('test'); it('cast()', () => { - type.cast(123).should.eql(123); + (type.cast(123) as number).should.eql(123); }); it('cast() - default', () => { const type = new SchemaType('test', {default: 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); it('cast() - default - function', () => { const type = new SchemaType('test', {default: () => 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); it('validate()', () => { - type.validate(123).should.eql(123); + (type.validate(123) as number).should.eql(123); }); it('validate() - required', () => { @@ -127,12 +127,12 @@ describe('SchemaType', () => { }); it('u$set', () => { - type.u$set(1, 1).should.eql(1); + type.u$set(1, 1).should.eql(1); }); it('u$unset', () => { should.not.exist(type.u$unset(1, true)); - type.u$unset(1, false).should.eql(1); + (type.u$unset(1, false) as number).should.eql(1); }); it('u$rename', () => { diff --git a/test/scripts/types/array.ts b/test/scripts/types/array.ts index 19ba5313..61cd52ba 100644 --- a/test/scripts/types/array.ts +++ b/test/scripts/types/array.ts @@ -13,12 +13,12 @@ describe('SchemaTypeArray', () => { type.cast('foo').should.eql(['foo']); type.cast([]).should.eql([]); type.cast([1, 2, 3]).should.eql([1, 2, 3]); - type.cast().should.eql([]); + (type.cast() as any[]).should.eql([]); }); it('cast() - default', () => { const type = new SchemaTypeArray('test', {default: [1, 2, 3]}); - type.cast().should.eql([1, 2, 3]); + (type.cast() as any[]).should.eql([1, 2, 3]); }); it('cast() - child', () => { diff --git a/test/scripts/types/buffer.ts b/test/scripts/types/buffer.ts index 9bae4b19..90ee44c9 100644 --- a/test/scripts/types/buffer.ts +++ b/test/scripts/types/buffer.ts @@ -25,7 +25,7 @@ describe('SchemaTypeBuffer', () => { const buf = Buffer.from([97, 98, 99]); const type = new SchemaTypeBuffer('test', {default: buf}); - type.cast().should.eql(buf); + (type.cast() as Buffer).should.eql(buf); }); function shouldThrowError(value) { @@ -50,7 +50,9 @@ describe('SchemaTypeBuffer', () => { it('match()', () => { type.match(Buffer.from([97, 98, 99]), Buffer.from([97, 98, 99])).should.be.true; type.match(Buffer.from([97, 98, 99]), Buffer.from([97, 98, 100])).should.be.false; + // @ts-ignore type.match(undefined, Buffer.from([97, 98, 99])).should.be.false; + // @ts-ignore type.match(undefined, undefined).should.be.true; }); diff --git a/test/scripts/types/date.ts b/test/scripts/types/date.ts index da80826b..49a55ca3 100644 --- a/test/scripts/types/date.ts +++ b/test/scripts/types/date.ts @@ -16,7 +16,7 @@ describe('SchemaTypeDate', () => { const date = new Date(); const type = new SchemaTypeDate('test', {default: date}); - type.cast().should.eql(date); + (type.cast() as Date).should.eql(date); }); function shouldThrowError(value) { @@ -42,7 +42,9 @@ describe('SchemaTypeDate', () => { it('match()', () => { type.match(new Date(2014, 1, 1), new Date(2014, 1, 1)).should.be.true; type.match(new Date(2014, 1, 1), new Date(2014, 1, 2)).should.be.false; + // @ts-ignore type.match(undefined, new Date()).should.be.false; + // @ts-ignore type.match(undefined, undefined).should.be.true; }); diff --git a/test/scripts/types/enum.ts b/test/scripts/types/enum.ts index ded35ace..7804322b 100644 --- a/test/scripts/types/enum.ts +++ b/test/scripts/types/enum.ts @@ -7,7 +7,7 @@ describe('SchemaTypeEnum', () => { it('validate()', () => { const type = new SchemaTypeEnum('test', {elements: ['foo', 'bar', 'baz']}); - type.validate('foo').should.eql('foo'); + (type.validate('foo') as string).should.eql('foo'); (() => type.validate('wat')).should.to.throw(ValidationError, 'The value must be one of foo, bar, baz'); }); diff --git a/test/scripts/types/number.ts b/test/scripts/types/number.ts index ae56afbf..3dd6003b 100644 --- a/test/scripts/types/number.ts +++ b/test/scripts/types/number.ts @@ -17,7 +17,7 @@ describe('SchemaTypeNumber', () => { it('cast() - default', () => { const type = new SchemaTypeNumber('type', {default: 42}); - type.cast().should.eql(42); + (type.cast() as number).should.eql(42); }); function shouldThrowError(value) { diff --git a/test/scripts/types/object.ts b/test/scripts/types/object.ts index e29b6473..960b651c 100644 --- a/test/scripts/types/object.ts +++ b/test/scripts/types/object.ts @@ -6,6 +6,6 @@ describe('SchemaTypeObject', () => { const type = new SchemaTypeObject('test'); it('cast() - default', () => { - type.cast().should.eql({}); + (type.cast() as object).should.eql({}); }); }); diff --git a/test/scripts/types/string.ts b/test/scripts/types/string.ts index b2572c8c..ebbda208 100644 --- a/test/scripts/types/string.ts +++ b/test/scripts/types/string.ts @@ -21,7 +21,7 @@ describe('SchemaTypeString', () => { it('cast() - default', () => { const type = new SchemaTypeString('test', {default: 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); function shouldThrowError(value) { diff --git a/test/scripts/types/virtual.ts b/test/scripts/types/virtual.ts index ddbc83c5..0d4880db 100644 --- a/test/scripts/types/virtual.ts +++ b/test/scripts/types/virtual.ts @@ -9,10 +9,11 @@ describe('SchemaTypeVirtual', () => { const getter = () => 'foo'; type.get(getter); - type.getter.should.eql(getter); + (type.getter as () => any).should.eql(getter); }); it('get() - type check', () => { + // @ts-ignore (() => type.get(123)).should.to.throw(TypeError, 'Getter must be a function!'); }); @@ -22,10 +23,11 @@ describe('SchemaTypeVirtual', () => { }; type.set(setter); - type.setter.should.eql(setter); + (type.setter as () => any).should.eql(setter); }); it('set() - type check', () => { + // @ts-ignore (() => type.set(123)).should.to.throw(TypeError, 'Setter must be a function!'); });