Setting up babel-typescript for Sequelize ORM can result in unspecified attributes being produced

Encountering an issue when combining sequelize-typescript with babel-preset-typescript. The challenge lies in retrieving columns using Object.defineProperty(), as existing properties are being skipped, leading to inconsistencies. While the regular typescript implementation works seamlessly with Sequelize†, switching to babel-typescript retains the unwanted properties.

Inquiry: How can I configure Babel to correctly ignore these unwanted properties?

Babel configurations (babel.config.js)

I've experimented with two different Babel configurations – one encompassing all desired features and another requiring explicit definitions.

Comprehensive definition

module.exports = {
  plugins: [
    [
      "@babel/plugin-transform-runtime",
      {
        regenerator: true,
      },
    ],
    "babel-plugin-inline-import",
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { legacy: true }],
    ["@babel/proposal-class-properties", { loose: true }],
    "@babel/proposal-object-rest-spread",
    "@babel/plugin-proposal-optional-chaining",
    [
      "module-resolver",
      {
        alias: {
          "~": "./src",
        },
      },
    ],
  ],
  presets: ["@babel/preset-env", "@babel/typescript"],
};

Condensed explicit definition

module.exports = {
  plugins: [
    ["@babel/proposal-decorators", { legacy: true }],
    ["@babel/proposal-class-properties", { loose: true }],
    "@babel/proposal-async-generator-functions",
    "@babel/proposal-object-rest-spread",
    "@babel/plugin-transform-runtime",
  ],
  presets: ["@babel/preset-env", "@babel/typescript"],
};

Context & specifics

You can find a standard non-babel example for testing here, where the branches babel_build and babel_explicit showcase different babel implementations.

The essence of defining a table involves simply adding decorators to the code:

import { Table, Column, Model } from 'sequelize-typescript'

@Table
class Person extends Model {
  @Column
  name: string

  @Column
  birthday: Date
}

The issue arises when attempting to retrieve data through:

const p = await Person.findOne({ name: "John Doe" })
console.log(p)

resulting in:

Person {
 dataValues: {
   id: 1,
   name: "John Doe",
   birthday: null
 },
  _previousDataValues: {
   id: 1,
   name: "John Doe",
   birthday: null
 },
  _changed: Set(0) {},
  _options: {
    isNewRecord: false,
    _schema: null,
    _schemaDelimiter: '',
    raw: true,
    attributes: [
      'id',
      'name',
      'birthday'
    ]
  },
  isNewRecord: false,
  name: undefined,
  birthday: undefined,
}

highlighting the issue with undefined values in the last rows.

Update - utilizing declare

Exploring further solutions suggests leveraging the declare keyword, although practical implementation proves challenging.

import { Table, Column, Model } from 'sequelize-typescript'

@Table
class Person extends Model {
  @Column
  declare name: string

  @Column
  declare birthday: Date
}

accompanied by the following configuration:

module.exports = {
  plugins: [
    ["@babel/plugin-transform-typescript", { allowDeclareFields: true }],
    [
      "@babel/plugin-transform-runtime",
      {
        regenerator: true,
      },
    ],
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { legacy: true }],
    ["@babel/proposal-class-properties", { loose: true }],
    [
      "module-resolver",
      {
        alias: {
          "~": "./src",
        },
      },
    ],
  ],
  presets: ["@babel/preset-env"],
};

Despite efforts, the problem persists, indicating that while declare may align more closely with the intended use, it falls short in practice.

† this discrepancy likely transcends the additions made by sequelize-typescript

Answer №1

Latest Update: 2022-01-21

It is recommended to utilize the declare keyword instead of using public ....

Here's an example:

class User extends Model<UserAttributes, UserCreationAttributes>
  implements UserAttributes {
  //public id!: number; // Remember to use the `null assertion` `!` in strict mode.
  declare id: number;

  //public name!: string;
  declare name: string;

  //public preferredName!: string | null; // for nullable fields
  declare preferredName: string | null;

  // timestamps!
  //public readonly createdAt!: Date;
  declare readonly createdAt: Date;

Source references:

Original Response Review

As per information from https://sequelize.org/master/manual/typescript.html, the model initialization definition in TypeScript is correct, yet there seems to be a discrepancy in the documentation.

By utilizing the null assertion (

public id!: number; // Note that the "null assertion" "!" is required in strict mode
), the attribute is set as undefined during instance initialization.

The proposed solution involves enforcing model initialization through getDataValue() within the Model Constructor and avoiding the suggested null assertion.

Illustrative Example

import {
  BuildOptions,
  Sequelize,
  Model,
  Optional,
} from "sequelize";

const sequelize = new Sequelize("mysql://root:asd123@localhost:3306/mydb");

// Defining all attributes within the User model
interface UserAttributes {
  id: number;
  name: string;
  //preferredName!: string | null;
  preferredName: string | null;
}

// Certain attributes are optional in `User.build` and `User.create` invocations
interface UserCreationAttributes extends Optional<UserAttributes, "id"> {}

class User extends Model<UserAttributes, UserCreationAttributes>
  implements UserAttributes {
  //public id!: number; // Note that the `null assertion` `!` is required in strict mode.
  public id: number;

  //public name!: string;
  public name: string;

  //public preferredName!: string | null; // for nullable fields
  public preferredName: string | null;

  // Timestamps declaration
  //public readonly createdAt!: Date;
  public readonly createdAt: Date;

  //public readonly updatedAt!: Date;
  public readonly updatedAt: Date;

  /**
   * Initialization method to address Sequelize Issue #11675.
   *
   * @see https://stackoverflow.com/questions/66515762/configuring-babel-typescript-for-sequelize-orm-causes-undefined-properties
   * @see https://github.com/sequelize/sequelize/issues/11675
   * @ref #SEQUELIZE-11675
   */
  constructor(values?: TCreationAttributes, options?: BuildOptions) {
    super(values, options);

    // Ensure all fields are accounted for here!
    this.id = this.getDataValue('id');
    this.name = this.getDataValue('name');
    this.preferredName = this.getDataValue('preferredName');
    this.createdAt = this.getDataValue('createdAt');
    this.updatedAt = this.getDataValue('updatedAt');
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can we set a specific length for an array passed in as a prop?

Can we use Typescript to specify the exact length of an array coming from props? Consider the following array of objects: const sampleArray = [ { key: '1', label: 'Label 1', value: 9 }, { key: '2', label: 'Label 2&ap ...

The attempt to bring in the model using `require` has resulted in an error. The `require` method used here, in combination with `path.join`, does

As a beginner in web development, I have been working on a project using MySQL, Node.js with Express. However, I am encountering a TypeError issue when using Sequelize. Can anyone kindly explain this to me and assist me in finding a solution? "seque ...

Issue with blueprintjs/core type in JupyterLab Extension after running npm install

Developed a JLab extension and saved it to Git repository. Established a new environment and successfully pulled the code, which was also verified by a friend. Subsequently, included a new react object to the extension and pushed it back to Git in a fresh ...

Can inner function calls be mimicked?

Consider this scenario where a module is defined as follows: // utils.ts function innerFunction() { return 28; } function testing() { return innerFunction(); } export {testing} To write a unit test for the testing function and mock the return value ...

Could the selection determine if a value is exported?

Need help with updating a Typescript code snippet: export const defaultListingFormValues = { itemWeight: 1 } Is it possible to dynamically adjust the default value of itemWeight based on a selected category in a dropdown menu for a listing form? For ex ...

Customize radio buttons in React using React Hook Form. Personalize the

I am currently working on a form using react-hook-form to update data with two radio options. The form is able to read and display the data correctly, however, when I try to change the value, the interface does not update accordingly. Can anyone help me id ...

What is the best approach to configure a OneToOne relationship as optional for various subclass entities?

If I have a base class called Animal, with subclasses Dog and Cat. export class Animal extends BaseEntity{ @PrimaryGeneratedColumn() id:number; } @Entity() export class Cat extends Animal{ ... } @Entity() export class Dog extends Animal{ .. ...

Adjust the trpc error prior to dispatching the response

The statement in the documentation mentions that errors can be handled or changed, but fails to provide any instructions on how to achieve this. Unfortunately, my search for information on this matter was fruitless, so I am reaching out here in hopes of f ...

What is the best way to obscure a potential phone number within a string of text?

Utilizing Google Cloud DLP in node.js to censor phone numbers from a string, even if the string contains other words. Check out more information on how to use this feature here. For instance, I need to redact the phone number in the following sentence: Do ...

Implementing dynamic loading of script files in app.component.ts using Angular

I am currently working with Angular2 and TypeScript. Within my app.component.ts file, I need to dynamically load script files based on the current navigator language. To achieve this, I have added the following function in my home.component.ts: export cl ...

A function that takes in a type identifier and a portion of a type, and then outputs the full type

I'm currently facing a challenge with TypeScript generics. I have several types (referred to as Animals) that each have a unique attribute, "type." Additionally, I have a function called createAnimal which takes the type of animal and a partial object ...

How does TypeScript provide me with insights even before compiling with tsc?

As I follow the instructions for incorporating TypeScript into my existing React Native project here, the final step instructs me to: Run yarn tsc to type-check your new TypeScript files. However, when I check VSCode, I am already receiving feedback from ...

Passing a map from the SpringBoot backend to the Angular view and storing it in LocalStorage

I'm facing a challenge with this task. I am trying to transfer a Map from my Spring Boot backend to an Angular application. Controller @GetMapping("/dict") public Map<String, String> getAll(){ return dictionaryService.getAll(); } @ ...

Pattern for asynchronously constructing objects with a generic parent class

Is there a way to modify the constructWhenReady method so that it returns only Child, without any changes to the 'calling' code or the Child class? I am looking for a solution to implementing an async constructor, but existing solutions are not c ...

Using MongoDB to swap out an object within an array

I'm facing a challenge in replacing/updating an entire object in an array with its latest values, and I can't seem to make it work. Here's how the database looks: (Please note that there is only one main object in this collection) { ...

Angular typed controls allowing for a seamless user experience without the need to

Currently, I am in the process of updating some older forms to include stronger typing in order to address eslint errors. One recurring issue I have encountered is when using the .value operator on abstract controls, it causes an error in my IDE stating "U ...

Utilizing Visual Studio Code for setting breakpoints in Typescript Jasmine tests

Currently, I am in the process of configuring a launch setup in Visual Studio Code for debugging my unit tests. The unit tests are written in Typescript, and both the tests and the corresponding code are compiled into a single js file with a source map. ...

Retrieve a particular attribute from the response data using Typescript

Here is an example of the response data format: In a Typescript environment, how can I extract the value of the "_Name" property from the first item inside the "ResultList" array of the response data? By utilizing this.responseData$.subscribe(val => c ...

Why does the server attempt to load the chart in Angular 10 Universal using Amcharts 4?

I have experience with Angular, but I am now delving into the world of using Universal for SEO purposes. My goal is to integrate a map from amcharts 4, which works fine without Angular Universal. However, I am facing an issue where the server attempts to ...

What causes Typescript to accept some objects and reject others?

I find the behavior of the Typescript compiler quite perplexing in relation to this code. I am using JSON.parse to populate a class instance from another class instance's output of stringify. It seems like the return value of JSON.parse is simply a r ...