diff --git a/bookshelf/bookshelf-tests.ts b/bookshelf/bookshelf-tests.ts
new file mode 100644
index 0000000000..67580dae5f
--- /dev/null
+++ b/bookshelf/bookshelf-tests.ts
@@ -0,0 +1,100 @@
+///
+///
+
+import * as Knex from 'knex';
+import * as Bookshelf from 'bookshelf';
+
+var knex = Knex({
+ client: 'sqlite3',
+ connection: {
+ filename: ':memory:',
+ },
+});
+
+// Examples
+
+var bookshelf = Bookshelf(knex);
+
+class User extends bookshelf.Model {
+ get tableName() { return 'users'; }
+ messages() : Bookshelf.Collection {
+ return this.hasMany(Posts);
+ }
+}
+
+class Posts extends bookshelf.Model {
+ get tableName() { return 'messages'; }
+ tags() : Bookshelf.Collection {
+ return this.belongsToMany(Tag);
+ }
+}
+
+class Tag extends bookshelf.Model {
+ get tableName() { return 'tags'; }
+}
+
+new User({}).where('id', 1).fetch({withRelated: ['posts.tags']})
+.then(user => {
+ console.log(user.related('posts').toJSON());
+}).catch(err => {
+ console.error(err);
+});
+
+
+// Associations
+
+class Book extends bookshelf.Model {
+ get tableName() { return 'books'; }
+ summary() {
+ return this.hasOne(Summary);
+ }
+ pages() {
+ return this.hasMany(Pages);
+ }
+ authors() {
+ return this.belongsToMany(Author);
+ }
+}
+
+class Summary extends bookshelf.Model {
+ get tableName() { return 'summaries'; }
+ book() : Book {
+ return this.belongsTo(Book);
+ }
+}
+
+class Pages extends bookshelf.Model {
+ get tableName() { return 'pages'; }
+ book() {
+ return this.belongsTo(Book);
+ }
+}
+
+class Author extends bookshelf.Model {
+ get tableName() { return 'author'; }
+ books() {
+ return this.belongsToMany(Book);
+ }
+}
+
+class Site extends bookshelf.Model {
+ get tableName() { return 'sites'; }
+ photo() {
+ return this.morphOne(Photo, 'imageable');
+ }
+}
+
+class Post extends bookshelf.Model {
+ get tableName() { return 'posts'; }
+ photos() {
+ return this.morphMany(Photo, 'imageable');
+ }
+}
+
+class Photo extends bookshelf.Model {
+ get tableName() { return 'photos'; }
+ imageable() {
+ return this.morphTo('imageable', Site, Post);
+ }
+}
+
diff --git a/bookshelf/bookshelf-tests.ts.tscparams b/bookshelf/bookshelf-tests.ts.tscparams
new file mode 100644
index 0000000000..5f84b97777
--- /dev/null
+++ b/bookshelf/bookshelf-tests.ts.tscparams
@@ -0,0 +1 @@
+--noImplicitAny --module commonjs --target es5
diff --git a/bookshelf/bookshelf.d.ts b/bookshelf/bookshelf.d.ts
new file mode 100644
index 0000000000..0da1ce2d68
--- /dev/null
+++ b/bookshelf/bookshelf.d.ts
@@ -0,0 +1,313 @@
+// Type definitions for bookshelfjs v0.8.2
+// Project: http://bookshelfjs.org/
+// Definitions by: Andrew Schurman
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+///
+///
+
+declare module 'bookshelf' {
+ import knex = require('knex');
+ import Promise = require('bluebird');
+ import Lodash = require('lodash');
+
+ interface Bookshelf extends Bookshelf.Events {
+ VERSION : string;
+ knex : knex;
+ Model : typeof Bookshelf.Model;
+ Collection : typeof Bookshelf.Collection;
+
+ transaction(callback : (transaction : knex.Transaction) => T) : Promise;
+ }
+
+ function Bookshelf(knex : knex) : Bookshelf;
+
+ namespace Bookshelf {
+ abstract class Events {
+ on(event? : string, callback? : EventFunction, context? : any) : void;
+ off(event? : string) : void;
+ trigger(event? : string, ...args : any[]) : void;
+ triggerThen(name : string, ...args : any[]) : Promise;
+ once(event : string, callback : EventFunction, context? : any) : void;
+ }
+
+ interface IModelBase {
+ /** Should be declared as a getter instead of a plain property. */
+ hasTimestamps? : boolean|string[];
+ /** Should be declared as a getter instead of a plain property. Should be required, but cannot have abstract properties yet. */
+ tableName? : string;
+ }
+
+ abstract class ModelBase> extends Events> implements IModelBase {
+ /** If overriding, must use a getter instead of a plain property. */
+ idAttribute : string;
+
+ constructor(attributes? : any, options? : ModelOptions);
+
+ clear() : T;
+ clone() : T;
+ escape(attribute : string) : string;
+ format(attributes : any) : any;
+ get(attribute : string) : any;
+ has(attribute : string) : boolean;
+ hasChanged(attribute? : string) : boolean;
+ isNew() : boolean;
+ parse(response : any) : any;
+ previousAttributes() : any;
+ previous(attribute : string) : any;
+ related>(relation : string) : R | Collection;
+ serialize(options? : SerializeOptions) : any;
+ set(attribute?: {[key : string] : any}, options? : SetOptions) : T;
+ set(attribute : string, value? : any, options? : SetOptions) : T;
+ timestamp(options? : TimestampOptions) : any;
+ toJSON(options? : SerializeOptions) : any;
+ unset(attribute : string) : T;
+
+ // lodash methods
+ invert() : R;
+ keys() : string[];
+ omit(predicate? : Lodash.ObjectIterator, thisArg? : any) : R;
+ omit(...attributes : string[]) : R;
+ pairs() : any[][];
+ pick(predicate? : Lodash.ObjectIterator, thisArg? : any) : R;
+ pick(...attributes : string[]) : R;
+ values() : any[];
+ }
+
+ class Model> extends ModelBase {
+ static collection>(models? : T[], options? : CollectionOptions) : Collection;
+ static count(column? : string, options? : SyncOptions) : Promise;
+ /** @deprecated use Typescript classes */
+ static extend>(prototypeProperties? : any, classProperties? : any) : Function; // should return a type
+ static fetchAll>() : Promise>;
+ /** @deprecated should use `new` objects instead. */
+ static forge(attributes? : any, options? : ModelOptions) : T;
+
+ belongsTo>(target : {new(...args : any[]) : R}, foreignKey? : string) : R;
+ belongsToMany>(target : {new(...args : any[]) : R}, table? : string, foreignKey? : string, otherKey? : string) : Collection;
+ count(column? : string, options? : SyncOptions) : Promise;
+ destroy(options : SyncOptions) : void;
+ fetch(options? : FetchOptions) : Promise;
+ fetchAll(options? : FetchAllOptions) : Promise>;
+ hasMany>(target : {new(...args : any[]) : R}, foreignKey? : string) : Collection;
+ hasOne>(target : {new(...args : any[]) : R}, foreignKey? : string) : R;
+ load(relations : string|string[], options? : LoadOptions) : Promise;
+ morphMany>(target : {new(...args : any[]) : R}, name? : string, columnNames? : string[], morphValue? : string) : Collection;
+ morphOne>(target : {new(...args : any[]) : R}, name? : string, columnNames? : string[], morphValue? : string) : R;
+ morphTo(name : string, columnNames? : string[], ...target : typeof Model[]) : T;
+ morphTo(name : string, ...target : typeof Model[]) : T;
+ query(...query : string[]) : T;
+ query(query : {[key : string] : any}) : T;
+ query(callback : (qb : knex.QueryBuilder) => void) : T;
+ query() : knex.QueryBuilder;
+ refresh(options? : FetchOptions) : Promise;
+ resetQuery() : T;
+ save(key? : string, val? : string, options? : SaveOptions) : Promise;
+ save(attrs? : {[key : string] : any}, options? : SaveOptions) : Promise;
+ through>(interim : typeof Model, throughForeignKey? : string, otherKey? : string) : R | Collection;
+ where(properties : {[key : string] : any}) : T;
+ where(key : string, operatorOrValue : string|number|boolean, valueIfOperator? : string|number|boolean) : T;
+ }
+
+ abstract class CollectionBase> extends Events {
+ add(models : T[]|{[key : string] : any}[], options? : CollectionAddOptions) : Collection;
+ at(index : number) : T;
+ clone() : Collection;
+ fetch(options? : CollectionFetchOptions) : Promise>;
+ findWhere(match : {[key : string] : any}) : T;
+ get(id : any) : T;
+ invokeThen(name : string, ...args : any[]) : Promise;
+ parse(response : any) : any;
+ pluck(attribute : string) : any[];
+ pop() : void;
+ push(model : any) : Collection;
+ reduceThen(iterator : (prev : R, cur : T, idx : number, array : T[]) => R, initialValue : R, context : any) : Promise;
+ remove(model : T, options? : EventOptions) : T;
+ remove(model : T[], options? : EventOptions) : T[];
+ reset(model : any[], options? : CollectionAddOptions) : T[];
+ serialize(options? : SerializeOptions) : any;
+ set(models : T[]|{[key : string] : any}[], options? : CollectionSetOptions) : Collection;
+ shift(options? : EventOptions) : void;
+ slice(begin? : number, end? : number) : void;
+ toJSON(options? : SerializeOptions) : any;
+ unshift(model : any, options? : CollectionAddOptions) : void;
+ where(match : {[key : string] : any}, firstOnly : boolean) : T|Collection;
+
+ // lodash methods
+ all(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : boolean;
+ all(predicate? : R) : boolean;
+ any(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : boolean;
+ any(predicate? : R) : boolean;
+ chain() : Lodash.LoDashExplicitObjectWrapper;
+ collect(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ collect(predicate? : R) : T[];
+ contains(value : any, fromIndex? : number) : boolean;
+ countBy(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : Lodash.Dictionary;
+ countBy(predicate? : R) : Lodash.Dictionary;
+ detect(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T;
+ detect(predicate? : R) : T;
+ difference(...values : T[]) : T[];
+ drop(n? : number) : T[];
+ each(callback? : Lodash.ListIterator, thisArg? : any) : Lodash.List;
+ each(callback? : Lodash.DictionaryIterator, thisArg? : any) : Lodash.Dictionary;
+ each(callback? : Lodash.ObjectIterator, thisArg? : any) : T;
+ every(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : boolean;
+ every(predicate? : R) : boolean;
+ filter(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ filter(predicate? : R) : T[];
+ find(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T;
+ find(predicate? : R) : T;
+ first() : T;
+ foldl(callback? : Lodash.MemoIterator, accumulator? : R, thisArg? : any) : R;
+ foldr(callback? : Lodash.MemoIterator, accumulator? : R, thisArg? : any) : R;
+ forEach(callback? : Lodash.ListIterator, thisArg? : any) : Lodash.List;
+ forEach(callback? : Lodash.DictionaryIterator, thisArg? : any) : Lodash.Dictionary;
+ forEach(callback? : Lodash.ObjectIterator, thisArg? : any) : T;
+ groupBy(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : Lodash.Dictionary;
+ groupBy(predicate? : R) : Lodash.Dictionary;
+ head() : T;
+ include(value : any, fromIndex? : number) : boolean;
+ indexOf(value : any, fromIndex? : number) : number;
+ initial() : T[];
+ inject(callback? : Lodash.MemoIterator, accumulator? : R, thisArg? : any) : R;
+ invoke(methodName : string|Function, ...args : any[]) : any;
+ isEmpty() : boolean;
+ keys() : string[];
+ last() : T;
+ lastIndexOf(value : any, fromIndex? : number) : number;
+ map(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ map(predicate? : R) : T[];
+ max(predicate? : Lodash.ListIterator|string, thisArg? : any) : T;
+ max(predicate? : R) : T;
+ min(predicate? : Lodash.ListIterator|string, thisArg? : any) : T;
+ min(predicate? : R) : T;
+ reduce(callback? : Lodash.MemoIterator, accumulator? : R, thisArg? : any) : R;
+ reduceRight(callback? : Lodash.MemoIterator, accumulator? : R, thisArg? : any) : R;
+ reject(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ reject(predicate? : R) : T[];
+ rest() : T[];
+ select(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ select(predicate? : R) : T[];
+ shuffle() : T[];
+ size() : number;
+ some(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : boolean;
+ some(predicate? : R) : boolean;
+ sortBy(predicate? : Lodash.ListIterator|Lodash.DictionaryIterator|string, thisArg? : any) : T[];
+ sortBy(predicate? : R) : T[];
+ tail() : T[];
+ take(n? : number) : T[];
+ toArray() : T[];
+ without(...values : any[]) : T[];
+ }
+
+ class Collection> extends CollectionBase {
+ /** @deprecated use Typescript classes */
+ static extend(prototypeProperties? : any, classProperties? : any) : Function;
+ /** @deprecated should use `new` objects instead. */
+ static forge(attributes? : any, options? : ModelOptions) : T;
+
+ attach(ids : any[], options? : SyncOptions) : Promise>;
+ count(column? : string, options? : SyncOptions) : Promise;
+ create(model : {[key : string] : any}, options? : CollectionCreateOptions) : Promise;
+ detach(ids : any[], options? : SyncOptions) : Promise;
+ fetchOne(options? : CollectionFetchOneOptions) : Promise;
+ load(relations : string|string[], options? : SyncOptions) : Promise>;
+ query(...query : string[]) : Collection;
+ query(query : {[key : string] : any}) : Collection;
+ query(callback : (qb : knex.QueryBuilder) => void) : Collection;
+ query() : knex.QueryBuilder;
+ resetQuery() : Collection;
+ through>(interim : typeof Model, throughForeignKey? : string, otherKey? : string) : R | Collection;
+ updatePivot(attributes : any, options? : PivotOptions) : Promise;
+ withPivot(columns : string[]) : Collection;
+ }
+
+ interface ModelOptions {
+ tableName? : string;
+ hasTimestamps? : boolean;
+ parse? : boolean;
+ }
+
+ interface LoadOptions extends SyncOptions {
+ withRelated: string|any|any[];
+ }
+
+ interface FetchOptions extends SyncOptions {
+ require? : boolean;
+ columns? : string|string[];
+ withRelated? : string|any|any[];
+ }
+
+ interface FetchAllOptions extends SyncOptions {
+ require? : boolean;
+ }
+
+ interface SaveOptions extends SyncOptions {
+ method? : string;
+ defaults? : string;
+ patch? : boolean;
+ require? : boolean;
+ }
+
+ interface SerializeOptions {
+ shallow? : boolean;
+ omitPivot? : boolean;
+ }
+
+ interface SetOptions {
+ unset? : boolean;
+ }
+
+ interface TimestampOptions {
+ method? : string;
+ }
+
+ interface SyncOptions {
+ transacting? : knex.Transaction;
+ debug? : boolean;
+ }
+
+ interface CollectionOptions {
+ comparator? : boolean|string|((a : T, b : T) => number);
+ }
+
+ interface CollectionAddOptions extends EventOptions {
+ at? : number;
+ merge? : boolean;
+ }
+
+ interface CollectionFetchOptions {
+ require? : boolean;
+ withRelated? : string|string[];
+ }
+
+ interface CollectionFetchOneOptions {
+ require? : boolean;
+ columns? : string|string[];
+ }
+
+ interface CollectionSetOptions extends EventOptions {
+ add? : boolean;
+ remove? : boolean;
+ merge?: boolean;
+ }
+
+ interface PivotOptions {
+ query? : Function|any;
+ require? : boolean;
+ }
+
+ interface EventOptions {
+ silent? : boolean;
+ }
+
+ interface EventFunction {
+ (model: T, attrs: any, options: any) : Promise|void;
+ }
+
+ interface CollectionCreateOptions extends ModelOptions, SyncOptions, CollectionAddOptions, SaveOptions {}
+ }
+
+ export = Bookshelf;
+}