Skip to content

Commit b865840

Browse files
fix: typeof Model errors by using typeof Model generics (#900)
1 parent 7c467d4 commit b865840

24 files changed

+178
-92
lines changed

src/associations/belongs-to-many/belongs-to-many-association.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import {BelongsToManyOptions as OriginBelongsToManyOptions, Model, ThroughOptions} from "sequelize";
2-
31
import {BaseAssociation} from '../shared/base-association';
42
import {BelongsToManyOptions} from './belongs-to-many-options';
53
import {ModelNotInitializedError} from '../../model/shared/model-not-initialized-error';
@@ -8,44 +6,46 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
86
import {Association} from "../shared/association";
97
import {Sequelize} from "../../sequelize/sequelize/sequelize";
108
import {UnionAssociationOptions} from "../shared/union-association-options";
9+
import {ModelType} from "../../model/model/model";
10+
import {ThroughOptions} from "../through/through-options";
1111

12-
export class BelongsToManyAssociation extends BaseAssociation {
12+
export class BelongsToManyAssociation<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough> extends BaseAssociation<TCreationAttributes, TModelAttributes> {
1313

14-
constructor(associatedClassGetter: ModelClassGetter,
15-
protected options: BelongsToManyOptions) {
14+
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
15+
protected options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>) {
1616
super(associatedClassGetter, options);
1717
}
1818

1919
getAssociation(): Association {
2020
return Association.BelongsToMany;
2121
}
2222

23-
getSequelizeOptions(model: typeof Model,
23+
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>,
2424
sequelize: Sequelize): UnionAssociationOptions {
25-
const options: OriginBelongsToManyOptions = {...this.options as any};
25+
const options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough> = {...this.options};
2626
const associatedClass = this.getAssociatedClass();
2727
const throughOptions = this.getThroughOptions(sequelize);
2828

2929
const throughModel = typeof throughOptions === 'object' && typeof throughOptions.model !== "string" ? throughOptions.model : undefined;
3030
options.through = throughOptions;
31-
options.foreignKey = getForeignKeyOptions(model, throughModel, this.options.foreignKey);
32-
options.otherKey = getForeignKeyOptions(associatedClass, throughModel, this.options.otherKey);
31+
options.foreignKey = getForeignKeyOptions(model, throughModel as any, this.options.foreignKey);
32+
options.otherKey = getForeignKeyOptions(associatedClass, throughModel as any, this.options.otherKey);
3333

3434
return options;
3535
}
3636

37-
private getThroughOptions(sequelize: Sequelize): ThroughOptions | string {
37+
private getThroughOptions(sequelize: Sequelize): ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough> | string {
3838
const through = this.options.through;
3939
const throughModel = typeof through === 'object' ? through.model : through;
40-
const throughOptions: ThroughOptions =
40+
const throughOptions: ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough> =
4141
typeof through === 'object' ? {...through} : {} as any;
4242

4343
if (typeof throughModel === 'function') {
4444
const throughModelClass = sequelize.model(throughModel());
4545
if (!throughModelClass.isInitialized) {
4646
throw new ModelNotInitializedError(throughModelClass, 'Association cannot be resolved.');
4747
}
48-
throughOptions.model = throughModelClass;
48+
throughOptions.model = throughModelClass as any;
4949
} else {
5050
return throughModel;
5151
}

src/associations/belongs-to-many/belongs-to-many-options.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
33
import {ThroughOptions} from "../through/through-options";
44

55

6-
export type BelongsToManyOptions = {
6+
export type BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough> = {
77
[K in keyof OriginBelongsToManyOptions]: K extends 'through'
8-
? ModelClassGetter | string | ThroughOptions
8+
? ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string | ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough>
99
: OriginBelongsToManyOptions[K]
1010
};

src/associations/belongs-to-many/belongs-to-many.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ import {BelongsToManyAssociation} from './belongs-to-many-association';
33
import {ModelClassGetter} from "../../model/shared/model-class-getter";
44
import {addAssociation} from "../shared/association-service";
55

6-
export function BelongsToMany(associatedClassGetter: ModelClassGetter,
7-
through: ModelClassGetter | string,
8-
foreignKey?: string,
9-
otherKey?: string): Function;
10-
export function BelongsToMany(associatedClassGetter: ModelClassGetter,
11-
options: BelongsToManyOptions): Function;
12-
export function BelongsToMany(associatedClassGetter: ModelClassGetter,
13-
throughOrOptions: ModelClassGetter | string | BelongsToManyOptions,
14-
foreignKey?: string,
15-
otherKey?: string): Function {
6+
export function BelongsToMany<
7+
TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
8+
through: ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string,
9+
foreignKey?: string,
10+
otherKey?: string): Function;
11+
export function BelongsToMany<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
12+
options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>): Function;
13+
export function BelongsToMany<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
14+
throughOrOptions: ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string | BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>,
15+
foreignKey?: string,
16+
otherKey?: string): Function {
1617

1718
return (target: any, propertyName: string) => {
18-
let options: Partial<BelongsToManyOptions> = {foreignKey, otherKey};
19+
let options: Partial<BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>> = {foreignKey, otherKey};
1920

2021
if (typeof throughOrOptions === 'string' ||
2122
typeof throughOrOptions === 'function') {
@@ -28,7 +29,7 @@ export function BelongsToMany(associatedClassGetter: ModelClassGetter,
2829

2930
addAssociation(target, new BelongsToManyAssociation(
3031
associatedClassGetter,
31-
options as BelongsToManyOptions,
32+
options as BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>,
3233
)
3334
);
3435
};

src/associations/belongs-to/belongs-to-association.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import {BaseAssociation} from '../shared/base-association';
44
import {getForeignKeyOptions} from "../foreign-key/foreign-key-service";
55
import {ModelClassGetter} from "../../model/shared/model-class-getter";
66
import {Association} from "../shared/association";
7-
import {Model} from "../../model/model/model";
7+
import {ModelType} from "../../model/model/model";
88
import {UnionAssociationOptions} from "../shared/union-association-options";
99

10-
export class BelongsToAssociation extends BaseAssociation {
10+
export class BelongsToAssociation<TCreationAttributes, TModelAttributes> extends BaseAssociation<TCreationAttributes, TModelAttributes> {
1111

12-
constructor(associatedClassGetter: ModelClassGetter,
12+
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
1313
protected options: BelongsToOptions) {
1414
super(associatedClassGetter, options);
1515
}
@@ -18,7 +18,7 @@ export class BelongsToAssociation extends BaseAssociation {
1818
return Association.BelongsTo;
1919
}
2020

21-
getSequelizeOptions(model: typeof Model): UnionAssociationOptions {
21+
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>): UnionAssociationOptions {
2222
const associatedClass = this.getAssociatedClass();
2323
const foreignKey = getForeignKeyOptions(associatedClass, model, this.options.foreignKey);
2424

src/associations/belongs-to/belongs-to.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import {BelongsToAssociation} from './belongs-to-association';
44
import {ModelClassGetter} from "../../model/shared/model-class-getter";
55
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";
66

7-
export function BelongsTo(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
7+
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;
88

9-
export function BelongsTo(associatedClassGetter: ModelClassGetter, options?: BelongsToOptions): Function;
9+
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: BelongsToOptions): Function;
1010

11-
export function BelongsTo(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | BelongsToOptions): Function {
11+
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | BelongsToOptions): Function {
1212

1313
return (target: any, propertyName: string) => {
1414
const options: BelongsToOptions = getPreparedAssociationOptions(optionsOrForeignKey);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {ModelClassGetter} from "../../model/shared/model-class-getter";
22

3-
export interface ForeignKeyMeta {
3+
export interface ForeignKeyMeta<TCreationAttributes, TModelAttributes> {
44

5-
relatedClassGetter: ModelClassGetter;
5+
relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>;
66
foreignKey: string;
77
}

src/associations/foreign-key/foreign-key-service.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import {ForeignKeyOptions, Model} from "sequelize";
1+
import {ForeignKeyOptions} from "sequelize";
22

33
import {ForeignKeyMeta} from './foreign-key-meta';
44
import {ModelClassGetter} from "../../model/shared/model-class-getter";
5+
import {ModelType} from "../../model/model/model";
56

67
const FOREIGN_KEYS_KEY = 'sequelize:foreignKeys';
78

8-
export function getForeignKeyOptions(relatedClass: typeof Model,
9-
classWithForeignKey?: typeof Model,
10-
foreignKey?: string | ForeignKeyOptions): ForeignKeyOptions {
9+
export function getForeignKeyOptions<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(relatedClass: ModelType<TCreationAttributes, TModelAttributes>,
10+
classWithForeignKey?: ModelType<TCreationAttributesThrough, TModelAttributesThrough>,
11+
foreignKey?: string | ForeignKeyOptions): ForeignKeyOptions {
1112
let foreignKeyOptions: ForeignKeyOptions = {};
1213

1314
if (typeof foreignKey === 'string') {
@@ -36,9 +37,9 @@ export function getForeignKeyOptions(relatedClass: typeof Model,
3637
/**
3738
* Adds foreign key meta data for specified class
3839
*/
39-
export function addForeignKey(target: any,
40-
relatedClassGetter: ModelClassGetter,
41-
foreignKey: string): void {
40+
export function addForeignKey<TCreationAttributes, TModelAttributes>(target: any,
41+
relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
42+
foreignKey: string): void {
4243
let foreignKeys = getForeignKeys(target);
4344
if (!foreignKeys) {
4445
foreignKeys = [];
@@ -53,7 +54,7 @@ export function addForeignKey(target: any,
5354
/**
5455
* Returns foreign key meta data from specified class
5556
*/
56-
export function getForeignKeys(target: any): ForeignKeyMeta[] | undefined {
57+
export function getForeignKeys<TCreationAttributes, TModelAttributes>(target: any): ForeignKeyMeta<TCreationAttributes, TModelAttributes>[] | undefined {
5758
const foreignKeys = Reflect.getMetadata(FOREIGN_KEYS_KEY, target);
5859
if (foreignKeys) {
5960
return [...foreignKeys];

src/associations/foreign-key/foreign-key.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {addForeignKey} from "./foreign-key-service";
22
import {ModelClassGetter} from "../../model/shared/model-class-getter";
33

4-
export function ForeignKey(relatedClassGetter: ModelClassGetter): Function {
4+
export function ForeignKey<TCreationAttributes, TModelAttributes>(relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>): Function {
55
return (target: any, propertyName: string) => {
66
addForeignKey(target, relatedClassGetter, propertyName);
77
};

src/associations/has/has-association.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import {HasManyOptions, HasOneOptions, Model} from 'sequelize';
1+
import {HasManyOptions, HasOneOptions} from 'sequelize';
22

33
import {BaseAssociation} from '../shared/base-association';
44
import {getForeignKeyOptions} from "../foreign-key/foreign-key-service";
55
import {ModelClassGetter} from "../../model/shared/model-class-getter";
66
import {Association} from "../shared/association";
77
import {UnionAssociationOptions} from "../shared/union-association-options";
8+
import {ModelType} from '../../model/model/model';
89

9-
export class HasAssociation extends BaseAssociation {
10+
export class HasAssociation<TCreationAttributes, TModelAttributes> extends BaseAssociation<TCreationAttributes, TModelAttributes> {
1011

11-
constructor(associatedClassGetter: ModelClassGetter,
12+
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
1213
protected options: HasManyOptions | HasOneOptions,
1314
private association: Association) {
1415
super(associatedClassGetter, options);
@@ -18,7 +19,7 @@ export class HasAssociation extends BaseAssociation {
1819
return this.association;
1920
}
2021

21-
getSequelizeOptions(model: typeof Model): UnionAssociationOptions {
22+
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>): UnionAssociationOptions {
2223
const options = {...this.options};
2324
const associatedClass = this.getAssociatedClass();
2425

src/associations/has/has-many.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
55
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";
66
import {Association} from "../shared/association";
77

8-
export function HasMany(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
8+
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;
99

10-
export function HasMany(associatedClassGetter: ModelClassGetter, options?: HasManyOptions): Function;
10+
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: HasManyOptions): Function;
1111

12-
export function HasMany(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | HasManyOptions): Function {
12+
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | HasManyOptions): Function {
1313

1414
return (target: any, propertyName: string) => {
1515
const options: HasManyOptions = getPreparedAssociationOptions(optionsOrForeignKey);

src/associations/has/has-one.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
55
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";
66
import {Association} from "../shared/association";
77

8-
export function HasOne(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
8+
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;
99

10-
export function HasOne(associatedClassGetter: ModelClassGetter, options?: HasOneOptions): Function;
10+
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: HasOneOptions): Function;
1111

12-
export function HasOne(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | HasOneOptions): Function {
12+
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | HasOneOptions): Function {
1313

1414
return (target: any, propertyName: string) => {
1515
const options: HasOneOptions = getPreparedAssociationOptions(optionsOrForeignKey);

src/associations/shared/association-service.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export function getPreparedAssociationOptions(optionsOrForeignKey?: string | Non
2727
/**
2828
* Stores association meta data for specified class
2929
*/
30-
export function addAssociation(target: any,
31-
association: BaseAssociation) {
30+
export function addAssociation<TCreationAttributes, TModelAttributes>(target: any,
31+
association: BaseAssociation<TCreationAttributes, TModelAttributes>) {
3232

3333
let associations = getAssociations(target);
3434

@@ -42,20 +42,20 @@ export function addAssociation(target: any,
4242
/**
4343
* Returns association meta data from specified class
4444
*/
45-
export function getAssociations(target: any): BaseAssociation[] | undefined {
45+
export function getAssociations<TCreationAttributes, TModelAttributes>(target: any): BaseAssociation<TCreationAttributes, TModelAttributes>[] | undefined {
4646
const associations = Reflect.getMetadata(ASSOCIATIONS_KEY, target);
4747
if (associations) {
4848
return [...associations];
4949
}
5050
}
5151

52-
export function setAssociations(target: any, associations: BaseAssociation[]) {
52+
export function setAssociations<TCreationAttributes, TModelAttributes>(target: any, associations: BaseAssociation<TCreationAttributes, TModelAttributes>[]) {
5353
Reflect.defineMetadata(ASSOCIATIONS_KEY, associations, target);
5454
}
5555

56-
export function getAssociationsByRelation(target: any,
57-
relatedClass: any): BaseAssociation[] {
58-
const associations = getAssociations(target);
56+
export function getAssociationsByRelation<TCreationAttributes, TModelAttributes>(target: any,
57+
relatedClass: any): BaseAssociation<TCreationAttributes, TModelAttributes>[] {
58+
const associations = getAssociations<TCreationAttributes, TModelAttributes>(target);
5959
return (associations || []).filter(association => {
6060
const _relatedClass = association.getAssociatedClass();
6161
return (

0 commit comments

Comments
 (0)