sequelize: Sequelize with TypeScript - class fields undefined
What are you doing?
I’am using Babel for code compilation + TypeScript for type-checking. Two scenarios:
- Using define, which is “really wouldn’t recommend this” (according types/test/define.ts comments)
interface User extends Model {
id: number;
login: string;
}
type UserModel = {
new (): User;
} & typeof Model;
const User = sequelize.define(
'User',
{ login: DataTypes.STRING },
{ tableName: 'user' }
) as UserModel;
- Using new approach (based on code, found in the types/models/User.ts)
export class User extends Model {
public id: number;
public login: string;
}
User = User.init(
{ login: DataTypes.STRING },
{ sequelize, tableName: 'user' }
);
In DB (Postgres) I have one row with login ‘admin’.
For the test, I use this function.
async function test() {
const user = (await User.findOne()) as User;
console.log('login', user.login, user.get('login'));
}
test();
What do you expect to happen?
It is logical that in both scenarios I should get
login admin admin
What is actually happening?
However, if in “modern”, second approach I see
login undefined admin
And if I print console.log(user) I see
user1 User {
dataValues:
{ id: 1,
login: 'admin',
createdAt: 2019-03-18T23:00:33.516Z,
updatedAt: 2019-03-18T23:00:33.516Z },
_previousDataValues:
{ id: 1,
login: 'admin',
createdAt: 2019-03-18T23:00:33.516Z,
updatedAt: 2019-03-18T23:00:33.516Z },
_changed: {},
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: false,
underscored: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: {},
indexes: [],
name: { plural: 'Users', singular: 'User' },
omitNull: false,
sequelize:
Sequelize {
options: [Object],
config: [Object],
dialect: [PostgresDialect],
queryInterface: [QueryInterface],
models: [Object],
modelManager: [ModelManager],
connectionManager: [ConnectionManager],
importCache: {},
test: [Object] },
tableName: 'user',
hooks: {} },
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [ 'id', 'login', 'createdAt', 'updatedAt' ] },
isNewRecord: false,
id: undefined,
login: undefined }
Dialect: postgres “sequelize”: “^5.1.0”,
upd: Just tested with ts-node - everything works as it should. Here is my .babelrc
{
"sourceMaps": "inline",
"retainLines": true,
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": true
}
}
],
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-object-rest-spread",
"@babel/proposal-class-properties"
]
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 4
- Comments: 41 (6 by maintainers)
Commits related to this issue
- fix(typescript): do not use const enums (#10585) Fixes #10579 — committed to sequelize/sequelize by SimonSchick 5 years ago
Please reopen
The solution for me was to set
"target": "ES2020"
intsnconfig.json
(it was set to ESNEXT)Closed huh? Reopen this.
This is still an issue for me. TypeScript v4.0.3 and Sequelize v6.3.5 in a Next.js v9.5.3 project using Node v14.6.0
Model Definition:
Ran into this issue today, hacking the constructor would’ve been too ugly, and also would’ve differed from vanilla JS behavior, so I created a little babel plugin to do this job:
Babel plugin to remove relevant attributes before they hit the transpiler
same plugin but with a hard boundary of directory defined
It works for me with Next.js default babel preset configured. Here’s what my
babel.config.js
looks likeExperiencing the same issue. Please reopen.
@Betree 's solution is nice, but doesn’t work with associations. Update this solution for associations:
then,
Please reopen, I still don’t see any normal solution
If anyone stumbles upon this issue on a new project, I managed to get around it by:
@aaahrens If I remember correctly, a solution was to do it this way:
Even though it’s not pretty.
The only other solution I see, is remove the
babel-plugin-proposal-class-properties
and upgrade to node 12 which supports class properties natively 😕Here is the generated code by babel with the typescript preset:
I believe the problem is that the super call sets the fields, but then they’re setted to
undefined
by the_defineProperty
function 😕@SimonSchick It might be useful to call the
_initValues
from the child class?Same issue with raw Typescript example starting version 4.3, because now
tsc
generates empty fieldsinstead of
I have the same issue, would love to see an even more elegant solution
For those who are still scrumbling and asking why @wlchn answer is not working with associations - here you are:
And in constructor:
Also this should not be closed, and the code behind Sequelize Mixins should be refactored
Same problem here in similar setup (Typescript 4, Sequelize 6, NextJS 9.5.5 & Node 14.15.1). “@babel/plugin-proposal-class-properties” is required by next.js, seems to cause this bug.
So the cleanest solution I’ve come up with so far is based on a hack proposed by @RobinBuschmann in https://github.com/RobinBuschmann/sequelize-typescript/issues/612#issuecomment-491890977.
The helper:
Then in each class, add a special constructor:
This is not perfect, I’d love to see a better solution if anyone has one.
It’s a problem generated by the
babel-plugin-proposal-class-properties
. Do you know any what to fix this @SimonSchick? Maybe we can call a setup method from the constructor.I have the same problem when use class definition. I resolve this issue by change to the default way of defining a model. It older but works. I have tested for feature Transaction and Association still work. this is my solution.
Nextjs version: 11.1.2 Sequelize: 6.6.5 Typescript: 4.4.4
This is not really a solution, but dropping babel in favor of esbuild fixed this for me, plus, it’s less configuration than babel+webpack.
For me, the solution has been stop using sequelize, and change to MikroORM
@steelbrain THANK YOU! You are a life saver.
For some reason though, for all my models,
bodyItem.accessibility
was always undefined, but as soon as I removed that condition from the filter under// Remove public class properties with no values
, it started working. This is definitely beyond my understanding, so not sure why that was the case for me or whether I’ve broken something else I haven’t realized yet by removing that check.Also worth mentioning that just adding the plugin won’t cause next to recompile if you’re running the dev server. Nuking the
.next
directory was the easiest thing for me to do make sure my models were recompiled using the new plugin.Same problem here, with node > 12 and not using
babel-plugin-proposal-class-properties
. @Telokis’s solution above works (thanks for sharing it!) but generates a warningProperty '...' is used before its initialization.
.Have to add
// @ts-ignore Property is used before its initialization
all over the place, which can’t be a long term solution for us. Will share progress if I find a better one.@DanielRamosAcosta Thanks for the answer
I’m having the same problem @petrovi4, how did you solved it?