Skip to content

Commit 581fd57

Browse files
Merge pull request #189 from schmod/model-type-inference
Type inference for static Model methods
2 parents 57f044c + 0cd0fb9 commit 581fd57

File tree

12 files changed

+1938
-591
lines changed

12 files changed

+1938
-591
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,10 @@ export class User extends Model<User> {}
221221
### Build and create
222222
Instantiation and inserts can be achieved in the good old sequelize way
223223
```typescript
224-
const person = Person.build<Person>({name: 'bob', age: 99});
224+
const person = Person.build({name: 'bob', age: 99});
225225
person.save();
226226

227-
Person.create<Person>({name: 'bob', age: 99});
227+
Person.create({name: 'bob', age: 99});
228228
```
229229
but *sequelize-typescript* also makes it possible to create instances with `new`:
230230
```typescript
@@ -237,15 +237,15 @@ Finding and updating entries does also work like using native sequelize. So see
237237
[docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html) for more details.
238238
```typescript
239239
Person
240-
.findOne<Person>()
240+
.findOne()
241241
.then(person => {
242242

243243
person.age = 100;
244244
return person.save();
245245
});
246246

247247
Person
248-
.update<Person>({
248+
.update({
249249
name: 'bobby'
250250
}, {where: {id: 1}})
251251
.then(() => {
@@ -290,7 +290,7 @@ That's all, *sequelize-typescript* does everything else for you. So when retriev
290290
```typescript
291291

292292
Team
293-
.findOne<Team>({include: [Player]})
293+
.findOne({include: [Player]})
294294
.then(team => {
295295

296296
team.players.forEach(player => console.log(`Player ${player.name}`));

lib/annotations/Column.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function annotate(target: any,
4040
};
4141
} else {
4242

43-
options = Object.assign({}, optionsOrDataType);
43+
options = Object.assign({}, <IPartialDefineAttributeColumnOptions>optionsOrDataType);
4444

4545
if (!options.type) {
4646
options.type = getSequelizeTypeByDesignType(target, propertyName);

lib/models/Model.d.ts

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export declare abstract class Model<T> extends Hooks {
5757
* @param schema The name of the schema
5858
* @param options
5959
*/
60-
static schema<T extends Model<T>>(schema: string, options?: SchemaOptions): Model<T>;
60+
static schema<T extends Model<T>>(this: (new () => T), schema: string, options?: SchemaOptions): Model<T>;
6161

6262
/**
6363
* Get the tablename of the model, taking schema into account. The method will return The name as a string
@@ -130,7 +130,7 @@ export declare abstract class Model<T> extends Hooks {
130130
* @return Model A reference to the model, with the scope(s) applied. Calling scope again on the returned
131131
* model will clear the previous scope.
132132
*/
133-
static scope(options?: string | string[] | ScopeOptions | WhereOptions<any>): typeof Model;
133+
static scope<T extends Model<T>>(this: (new () => T), options?: string | string[] | ScopeOptions | WhereOptions<any>): typeof T;
134134

135135
/**
136136
* Search for multiple instances.
@@ -194,25 +194,25 @@ export declare abstract class Model<T> extends Hooks {
194194
*
195195
* @see {Sequelize#query}
196196
*/
197-
static findAll<T extends Model<T>>(options?: IFindOptions<T>): Promise<T[]>;
197+
static findAll<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<T[]>;
198198

199-
static all<T extends Model<T>>(options?: IFindOptions<T>): Promise<T[]>;
199+
static all<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<T[]>;
200200

201201
/**
202202
* Search for a single instance by its primary key. This applies LIMIT 1, so the listener will
203203
* always be called with a single instance.
204204
*/
205-
static findById<T extends Model<T>>(identifier?: number | string, options?: IFindOptions<T>): Promise<T | null>;
205+
static findById<T extends Model<T>>(this: (new () => T), identifier?: number | string, options?: IFindOptions<T>): Promise<T | null>;
206206

207-
static findByPrimary<T extends Model<T>>(identifier?: number | string, options?: IFindOptions<T>): Promise<T | null>;
207+
static findByPrimary<T extends Model<T>>(this: (new () => T), identifier?: number | string, options?: IFindOptions<T>): Promise<T | null>;
208208

209209
/**
210210
* Search for a single instance. This applies LIMIT 1, so the listener will always be called with a single
211211
* instance.
212212
*/
213-
static findOne<T extends Model<T>>(options?: IFindOptions<T>): Promise<T | null>;
213+
static findOne<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<T | null>;
214214

215-
static find<T extends Model<T>>(options?: IFindOptions<T>): Promise<T | null>;
215+
static find<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<T | null>;
216216

217217
/**
218218
* Run an aggregation method on the specified field
@@ -267,9 +267,9 @@ export declare abstract class Model<T> extends Hooks {
267267
* without
268268
* profiles will be counted
269269
*/
270-
static findAndCount<T extends Model<T>>(options?: IFindOptions<T>): Promise<{rows: T[], count: number}>;
270+
static findAndCount<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<{rows: T[], count: number}>;
271271

272-
static findAndCountAll<T extends Model<T>>(options?: IFindOptions<T>): Promise<{rows: T[], count: number}>;
272+
static findAndCountAll<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<{rows: T[], count: number}>;
273273

274274
/**
275275
* Find the maximum value of field
@@ -289,30 +289,35 @@ export declare abstract class Model<T> extends Hooks {
289289
/**
290290
* Builds a new model instance. Values is an object of key value pairs, must be defined but can be empty.
291291
*/
292-
static build<T extends Model<T>>(record?: any, options?: IBuildOptions): T;
293-
static build<T extends Model<T>, A>(record?: A, options?: IBuildOptions): T;
292+
static build<T extends Model<T>>(this: (new () => T), record?: any, options?: IBuildOptions): T;
293+
static build<T extends Model<T>, A>(this: (new () => T), record?: A, options?: IBuildOptions): T;
294+
static build<A>(this: (new () => T), record?: A, options?: IBuildOptions): T;
294295

295296
/**
296297
* Undocumented bulkBuild
297298
*/
298-
static bulkBuild<T extends Model<T>>(records: any[], options?: IBuildOptions): T[];
299-
static bulkBuild<T extends Model<T>, A>(records: A[], options?: IBuildOptions): T[];
299+
static bulkBuild<T extends Model<T>>(this: (new () => T), records: any[], options?: IBuildOptions): T[];
300+
static bulkBuild<T extends Model<T>, A>(this: (new () => T), records: A[], options?: IBuildOptions): T[];
301+
static bulkBuild<A>(this: (new () => T), records: A[], options?: IBuildOptions): T[];
300302

301303
/**
302304
* Builds a new model instance and calls save on it.
303305
*/
304-
static create<T extends Model<T>>(values?: any, options?: ICreateOptions): Promise<T>;
305-
static create<T extends Model<T>, A>(values?: A, options?: ICreateOptions): Promise<T>;
306+
static create<T extends Model<T>>(this: (new () => T), values?: any, options?: ICreateOptions): Promise<T>;
307+
static create<T extends Model<T>, A>(this: (new () => T), values?: A, options?: ICreateOptions): Promise<T>;
308+
static create<A>(this: (new () => T), values?: A, options?: ICreateOptions): Promise<T>;
306309

307310
/**
308311
* Find a row that matches the query, or build (but don't save) the row if none is found.
309312
* The successfull result of the promise will be (instance, initialized) - Make sure to use .spread()
310313
*/
311-
static findOrInitialize<T extends Model<T>>(options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
312-
static findOrInitialize<T extends Model<T>, A>(options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
314+
static findOrInitialize<T extends Model<T>>(this: (new () => T), options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
315+
static findOrInitialize<T extends Model<T>, A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
316+
static findOrInitialize<A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
313317

314-
static findOrBuild<T extends Model<T>>(options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
315-
static findOrBuild<T extends Model<T>, A>(options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
318+
static findOrBuild<T extends Model<T>>(this: (new () => T), options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
319+
static findOrBuild<T extends Model<T>, A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
320+
static findOrBuild<A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
316321

317322
/**
318323
* Find a row that matches the query, or build and save the row if none is found
@@ -325,15 +330,17 @@ export declare abstract class Model<T> extends Hooks {
325330
* an instance of sequelize.TimeoutError will be thrown instead. If a transaction is created, a savepoint
326331
* will be created instead, and any unique constraint violation will be handled internally.
327332
*/
328-
static findOrCreate<T extends Model<T>>(options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
329-
static findOrCreate<T extends Model<T>, A>(options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
333+
static findOrCreate<T extends Model<T>>(this: (new () => T), options: IFindOrInitializeOptions<any>): Promise<[T, boolean]>;
334+
static findOrCreate<T extends Model<T>, A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
335+
static findOrCreate<A>(this: (new () => T), options: IFindOrInitializeOptions<A>): Promise<[T, boolean]>;
330336

331337
/**
332338
* A more performant findOrCreate that will not work under a transaction (at least not in postgres)
333339
* Will execute a find call, if empty then attempt to create, if unique constraint then attempt to find again
334340
*/
335-
static findCreateFind<T extends Model<T>>(options: IFindCreateFindOptions<any>): Promise<[T, boolean]>;
336-
static findCreateFind<T extends Model<T>, A>(options: IFindCreateFindOptions<A>): Promise<[T, boolean]>;
341+
static findCreateFind<T extends Model<T>>(this: (new () => T), options: IFindCreateFindOptions<any>): Promise<[T, boolean]>;
342+
static findCreateFind<T extends Model<T>, A>(this: (new () => T), options: IFindCreateFindOptions<A>): Promise<[T, boolean]>;
343+
static findCreateFind<A>(this: (new () => T), options: IFindCreateFindOptions<A>): Promise<[T, boolean]>;
337344

338345
/**
339346
* Insert or update a single row. An update will be executed if a row which matches the supplied values on
@@ -369,8 +376,9 @@ export declare abstract class Model<T> extends Hooks {
369376
*
370377
* @param records List of objects (key/value pairs) to create instances from
371378
*/
372-
static bulkCreate<T extends Model<T>>(records: any[], options?: BulkCreateOptions): Promise<T[]>;
373-
static bulkCreate<T extends Model<T>, A>(records: A[], options?: BulkCreateOptions): Promise<T[]>;
379+
static bulkCreate<T extends Model<T>>(this: (new () => T), records: any[], options?: BulkCreateOptions): Promise<T[]>;
380+
static bulkCreate<T extends Model<T>, A>(this: (new () => T), records: A[], options?: BulkCreateOptions): Promise<T[]>;
381+
static bulkCreate<A>(this: (new () => T), records: A[], options?: BulkCreateOptions): Promise<T[]>;
374382

375383
/**
376384
* Truncate all instances of the model. This is a convenient method for Model.destroy({ truncate: true }).
@@ -394,8 +402,9 @@ export declare abstract class Model<T> extends Hooks {
394402
* elements. The first element is always the number of affected rows, while the second element is the actual
395403
* affected rows (only supported in postgres with `options.returning` true.)
396404
*/
397-
static update<T extends Model<T>>(values: any, options: UpdateOptions): Promise<[number, Array<T>]>;
398-
static update<T extends Model<T>, A>(values: A, options: UpdateOptions): Promise<[number, Array<T>]>;
405+
static update<T extends Model<T>>(this: (new () => T), values: any, options: UpdateOptions): Promise<[number, Array<T>]>;
406+
static update<T extends Model<T>, A>(this: (new () => T), values: A, options: UpdateOptions): Promise<[number, Array<T>]>;
407+
static update<A>(this: (new () => T), values: A, options: UpdateOptions): Promise<[number, Array<T>]>;
399408

400409
/**
401410
* Run a describe query on the table. The result will be return to the listener as a hash of attributes and
@@ -406,7 +415,7 @@ export declare abstract class Model<T> extends Hooks {
406415
/**
407416
* Unscope the model
408417
*/
409-
static unscoped(): typeof Model;
418+
static unscoped<T extends Model<T>>(this: (new () => T)): typeof T;
410419

411420
/**
412421
* A reference to the sequelize instance

0 commit comments

Comments
 (0)