8

I'm trying to create a base crud service that takes a Sequelize model and creates all basic APIs for it so what I have done it this:

export class RepositoryService<T extends Model<T>> {
  constructor(protected model: typeof Model) {
  }
  public async getMany(
    query: RequestParamsParsed = {},
    options: RestfulOptions = {},
  ): Promise<T[]> {
    return this.model.findAll();
  }
}

I'm getting the following error:

The 'this' context of type 'typeof Model' is not assignable to method's 'this' of type 'new () => Model<Model<any>>'.
  Cannot assign an abstract constructor type to a non-abstract constructor type.

this is because of this line in the seqeulize-typescript package:

static findAll<T extends Model<T>>(this: (new () => T), options?: IFindOptions<T>): Promise<T[]>;

I'm relatively new to Typescript so if anyone can tell me what's the meaning of this: (new () => T) in the findAll function and how can I work this out.

1
  • arg: (new () => T) means that arg is not instance of type T like in (arg: T). arg is class T. Also you can use this syntax for that (arg: { new (...args): T }) Commented Mar 14, 2019 at 15:52

3 Answers 3

6

Also encountered this error while working with the sequelize-typescript library.

You could first define these helper types:

import { Model } from "sequelize-typescript";

// Type `ModelType` would basically wrap & satisfy the 'this' context of any sequelize helper methods
type Constructor<T> = new (...args: any[]) => T;
type ModelType<T extends Model<T>> = Constructor<T> & typeof Model;

Then, use it with your code:

export class RepositoryService<T extends Model<T>> {
  constructor(protected model: ModelType<T>) {}

  public async getMany(
    query: RequestParamsParsed = {},
    options: RestfulOptions = {},
  ): Promise<T[]> {
    return this.model.findAll();
  }
}

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

2

The problem seemed to be in this line

constructor(protected model: typeof Model) {}

The Model I was setting the model type to is imported from sequelize-typescript while I should use the original model exported from sequelize itself.

The whole code is like this:

import { Model as OriginalModel } from 'sequelize';
import { Model } from 'sequelize-typescript';
export class RepositoryService<T extends Model<T>> {
  constructor(protected model: typeof OriginalModel) {
  }
  public async getMany(
    query: RequestParamsParsed = {},
    options: RestfulOptions = {},
  ): Promise<T[]> {
    return this.model.findAll();
  }
}

1 Comment

Better solution from @Adrian below.
2

Using "sequelize-typescript": "2.1.0" you can use ModelCtor provided by the module eg.

import { Model, ModelCtor } from 'sequelize-typescript';

export class RepositoryService<T extends Model<T>> {
  constructor(protected model: ModelCtor<T>) {}

  public async getMany(
    query: RequestParamsParsed = {}, 
    options: RestfulOptions = {}
): Promise<T[]> {
    return this.model.findAll();
  }
}

The ModelCtor type is:

export declare type Repository<M> = (new () => M) & NonAbstract<typeof Model>;

export declare type ModelCtor<M extends Model = Model> = Repository<M>;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.