不要怂,就是干,撸起袖子干!

Commit 0b868c83 by Rémy Dufour Committed by Sushant

feat(types): add generics types for associations (#10524)

1 parent 35780624
import { ColumnOptions, Model } from '../model'; import { ColumnOptions, Model, ModelCtor } from '../model';
export abstract class Association { export abstract class Association<S extends Model = Model, T extends Model = Model> {
public associationType: string; public associationType: string;
public source: typeof Model; public source: ModelCtor<S>;
public target: typeof Model; public target: ModelCtor<T>;
public isSelfAssociation: boolean; public isSelfAssociation: boolean;
public isSingleAssociation: boolean; public isSingleAssociation: boolean;
public isMultiAssociation: boolean; public isMultiAssociation: boolean;
......
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
InstanceDestroyOptions, InstanceDestroyOptions,
InstanceUpdateOptions, InstanceUpdateOptions,
Model, Model,
ModelCtor,
Transactionable, Transactionable,
WhereOptions, WhereOptions,
} from '../model'; } from '../model';
...@@ -68,10 +69,10 @@ export interface BelongsToManyOptions extends ManyToManyOptions { ...@@ -68,10 +69,10 @@ export interface BelongsToManyOptions extends ManyToManyOptions {
timestamps?: boolean; timestamps?: boolean;
} }
export class BelongsToMany extends Association { export class BelongsToMany<S extends Model = Model, T extends Model = Model> extends Association<S, T> {
public otherKey: string; public otherKey: string;
public accessors: MultiAssociationAccessors; public accessors: MultiAssociationAccessors;
constructor(source: typeof Model, target: typeof Model, options: BelongsToManyOptions); constructor(source: ModelCtor<S>, target: ModelCtor<T>, options: BelongsToManyOptions);
} }
/** /**
......
import { DataType } from '../data-types'; import { DataType } from '../data-types';
import { CreateOptions, FindOptions, Model, SaveOptions } from '../model'; import { CreateOptions, FindOptions, Model, ModelCtor, SaveOptions } from '../model';
import { Promise } from '../promise'; import { Promise } from '../promise';
import { Association, AssociationOptions, SingleAssociationAccessors } from './base'; import { Association, AssociationOptions, SingleAssociationAccessors } from './base';
// type ModelCtor<M extends Model> = InstanceType<typeof M>;
/** /**
* Options provided when associating models with belongsTo relationship * Options provided when associating models with belongsTo relationship
* *
...@@ -21,9 +22,9 @@ export interface BelongsToOptions extends AssociationOptions { ...@@ -21,9 +22,9 @@ export interface BelongsToOptions extends AssociationOptions {
keyType?: DataType; keyType?: DataType;
} }
export class BelongsTo extends Association { export class BelongsTo<S extends Model = Model, T extends Model = Model> extends Association<S, T> {
public accessors: SingleAssociationAccessors; public accessors: SingleAssociationAccessors;
constructor(source: typeof Model, target: typeof Model, options: BelongsToOptions); constructor(source: ModelCtor<S>, target: ModelCtor<T>, options: BelongsToOptions);
} }
/** /**
......
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
FindOptions, FindOptions,
InstanceUpdateOptions, InstanceUpdateOptions,
Model, Model,
ModelCtor,
Transactionable, Transactionable,
WhereOptions, WhereOptions,
} from '../model'; } from '../model';
...@@ -22,9 +23,9 @@ export interface HasManyOptions extends ManyToManyOptions { ...@@ -22,9 +23,9 @@ export interface HasManyOptions extends ManyToManyOptions {
keyType?: DataType; keyType?: DataType;
} }
export class HasMany extends Association { export class HasMany<S extends Model = Model, T extends Model = Model> extends Association<S, T> {
public accessors: MultiAssociationAccessors; public accessors: MultiAssociationAccessors;
constructor(source: typeof Model, target: typeof Model, options: HasManyOptions); constructor(source: ModelCtor<S>, target: ModelCtor<T>, options: HasManyOptions);
} }
/** /**
......
import { DataType } from '../data-types'; import { DataType } from '../data-types';
import { CreateOptions, FindOptions, Model, SaveOptions } from '../model'; import { CreateOptions, FindOptions, Model, ModelCtor, SaveOptions } from '../model';
import { Promise } from '../promise'; import { Promise } from '../promise';
import { Association, AssociationOptions, SingleAssociationAccessors } from './base'; import { Association, AssociationOptions, SingleAssociationAccessors } from './base';
...@@ -13,9 +13,9 @@ export interface HasOneOptions extends AssociationOptions { ...@@ -13,9 +13,9 @@ export interface HasOneOptions extends AssociationOptions {
keyType?: DataType; keyType?: DataType;
} }
export class HasOne extends Association { export class HasOne<S extends Model = Model, T extends Model = Model> extends Association<S, T> {
public accessors: SingleAssociationAccessors; public accessors: SingleAssociationAccessors;
constructor(source: typeof Model, target: typeof Model, options: HasOneOptions); constructor(source: ModelCtor<S>, target: ModelCtor<T>, options: HasOneOptions);
} }
/** /**
......
...@@ -2192,7 +2192,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2192,7 +2192,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param target The model that will be associated with hasOne relationship * @param target The model that will be associated with hasOne relationship
* @param options Options for the association * @param options Options for the association
*/ */
public static hasOne(target: typeof Model, options?: HasOneOptions): HasOne; public static hasOne<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: HasOneOptions
): HasOne<M, T>;
/** /**
* Creates an association between this (the source) and the provided target. The foreign key is added on the * Creates an association between this (the source) and the provided target. The foreign key is added on the
...@@ -2203,8 +2205,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2203,8 +2205,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param target The model that will be associated with hasOne relationship * @param target The model that will be associated with hasOne relationship
* @param options Options for the association * @param options Options for the association
*/ */
public static belongsTo(target: typeof Model, options?: BelongsToOptions): BelongsTo; public static belongsTo<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: BelongsToOptions
): BelongsTo<M, T>;
/** /**
* Create an association that is either 1:m or n:m. * Create an association that is either 1:m or n:m.
* *
...@@ -2257,7 +2261,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2257,7 +2261,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param target The model that will be associated with hasOne relationship * @param target The model that will be associated with hasOne relationship
* @param options Options for the association * @param options Options for the association
*/ */
public static hasMany(target: typeof Model, options?: HasManyOptions): HasMany; public static hasMany<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: HasManyOptions
): HasMany<M, T>;
/** /**
* Create an N:M association with a join table * Create an N:M association with a join table
...@@ -2307,7 +2313,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2307,7 +2313,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options Options for the association * @param options Options for the association
* *
*/ */
public static belongsToMany(target: typeof Model, options: BelongsToManyOptions): BelongsToMany; public static belongsToMany<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options: BelongsToManyOptions
): BelongsToMany<M, T>;
/** /**
* Returns true if this instance has not yet been persisted to the database * Returns true if this instance has not yet been persisted to the database
...@@ -2511,4 +2519,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2511,4 +2519,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
public toJSON(): object; public toJSON(): object;
} }
export type ModelType = typeof Model;
export type ModelCtor<M extends Model> = { new (): M } & ModelType;
export default Model; export default Model;
...@@ -6,12 +6,13 @@ import { ...@@ -6,12 +6,13 @@ import {
DataTypes, DataTypes,
FindOptions, FindOptions,
Model, Model,
ModelCtor
} from 'sequelize'; } from 'sequelize';
import { sequelize } from '../connection'; import { sequelize } from '../connection';
export class User extends Model { export class User extends Model {
public static associations: { public static associations: {
group: BelongsTo group: BelongsTo<User, UserGroup>;
}; };
public id: number; public id: number;
...@@ -68,7 +69,12 @@ User.afterFind((users, options) => { ...@@ -68,7 +69,12 @@ User.afterFind((users, options) => {
User.addHook('beforeFind', 'test', (options: FindOptions) => { User.addHook('beforeFind', 'test', (options: FindOptions) => {
return undefined; return undefined;
}); });
// associate // associate
// it is important to import _after_ the model above is already exported so the circular reference works. // it is important to import _after_ the model above is already exported so the circular reference works.
import { UserGroup } from './UserGroup'; import { UserGroup } from './UserGroup';
export const Group = User.belongsTo(UserGroup, { as: 'group', foreignKey: 'groupId' }); export const Group = User.belongsTo(UserGroup, { as: 'group', foreignKey: 'groupId' });
// associations refer to their Model
const userType: ModelCtor<User> = User.associations.group.source;
const groupType: ModelCtor<UserGroup> = User.associations.group.target;
...@@ -16,7 +16,7 @@ import { sequelize } from '../connection'; ...@@ -16,7 +16,7 @@ import { sequelize } from '../connection';
export class UserGroup extends Model { export class UserGroup extends Model {
public static associations: { public static associations: {
users: HasMany users: HasMany<UserGroup, User>
}; };
public id: number; public id: number;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!