rink.attendant.6
rink.attendant.6

Reputation: 46218

Sequelize model getters in TypeScript

What is the correct way of using this.getDataValue in a getter function for a Sequelize model when using TypeScript?

This is the error I'm getting:

Property 'getDataValue' does not exist on type 'string | DataTypeAbstract | DefineAttributeColumnOptions'.

Property 'getDataValue' does not exist on type 'string'.

My model definition:

import * as Sequelize from 'sequelize';
import sequelize from '../db-connection';

export interface IUserAttributes {
    date_of_birth: Date;
    name: string;
}

export interface IUserInstance extends Sequelize.Instance<IUserAttributes> {
    date_of_birth: Date;
    name: string;
}

const User = sequelize.define<IUserAttributes, IUserInstance>('user', {
    name: {
        type: Sequelize.STRING,
        validate: {
            notEmpty: true,
        },
    },
    date_of_birth: {
        get(): Date {
            return new Date(this.getDataValue('date_of_birth'));
        },
        type: Sequelize.DATEONLY,
        validate: {
            isDate: true,
            notEmpty: true,
        },
    },
});

export default User;

Upvotes: 5

Views: 10245

Answers (3)

Lin Du
Lin Du

Reputation: 102277

For "sequelize": "^5.21.3", "typescript": "^3.7.5" and define the sequelize model using TypeScript class based style.

index.ts:

import { sequelize } from '../../db';
import Sequelize, { Model } from 'sequelize';

class User extends Model {
  public date_of_birth!: Date;
  public name!: string;
}
User.init(
  {
    name: {
      type: Sequelize.STRING,
      validate: {
        notEmpty: true,
      },
    },
    date_of_birth: {
      get(this: User): Date {
        return new Date(this.getDataValue('date_of_birth'));
      },
      type: Sequelize.DATEONLY,
      validate: {
        isDate: true,
        notEmpty: true,
      },
    },
  },
  { sequelize, modelName: 'user' },
);

Cast this type to User class will get rid of the error. Don't forget to declare the properties in the User class.

Upvotes: 3

David Dehghan
David Dehghan

Reputation: 24785

Here is a working example> It casts the underlying TEXT value in column data to a new JSONB type column called payload:

import {DataTypes, Model, Sequelize} from 'sequelize';

export class Book extends Model {
    public id!: number; 
    public name!: string;
    public payload!: any;
    private data!: string;
}

export const initBook = (sequelize: Sequelize) => {
    Book.init(
        {
            id: {
                type: DataTypes.INTEGER,
                primaryKey: true
            },
            name: {
                type: DataTypes.STRING(100),
                primaryKey: false
            },
            data: {
                type: DataTypes.TEXT,
                primaryKey: false
            },               
            payload: {
                type: DataTypes.JSONB,
                allowNull: false,
                field: 'data',
                get(this: any) {
                    const j = this.getDataValue('payload');
                    return JSON.parse(j);
                }
            }               
        },
        {
            tableName: 'book',
            sequelize // this bit is important
        }
    );
};

export default {Book, initBook};

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249656

You need to specify the type for this inside the getter function

const User = sequelize.define<IUserAttributes, IUserInstance>('user', {
  name: {
      type: Sequelize.STRING,
      validate: {
          notEmpty: true,
      },
  },
  date_of_birth: {
      get(this: IUserInstance): Date {
          return new Date(this.getDataValue('date_of_birth'));
      },
      type: Sequelize.DATEONLY,
      validate: {
          isDate: true,
          notEmpty: true,
      },
  },
});

Note The this argument will not get emitted to JS it is just for the benefit of the typescript compiler.

Upvotes: 9

Related Questions