Sequelize TypeScript getters and setters - javascript

Environment
Sequelize version: 6.6.5
Node.js version: 14.17.6
If TypeScript related: 4.4.3
Dialect sqlite
When using typescript and getters/setters, if the column DataType does not match the interface/attribute type, typescript throws an error.
Example:
interface IUserAttributes {
id: number;
registeredAtIp: string;
}
interface IUserCreationAttributes extends Optional<IUserAttributes, 'id'> {}
class User extends Model<IUserAttributes, IUserCreationAttributes> implements IUserAttributes {
public id!: number;
public registeredAtIp!: string;
}
User.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
unique: true,
},
registeredAtIp: {
type: DataTypes.INTEGER,
allowNull: false,
get(): string {
return int2Ip(this.getDataValue("registeredAtIp"));
// ^
// Argument of type 'string' is not assignable to parameter of type 'number'.ts(2345)
// this: User
},
set(newIp: string): void {
this.setDataValue("registeredAtIp", ip2Int(newIp));
// ^
// Argument of type 'number' is not assignable to parameter of type 'string'.ts(2345)
// (alias) ip2Int(ip: string): number
// import ip2Int
},
},
},
{ sequelize, tableName: "users" }
);
Shouldn't getDataValue return number as the column DataType is INTEGER and not string?
Setting the interface type to number fixes the error but I can't create a User which has the property as a string.
I want to know how to stop the error, aka this.getDataValue('registeredAtIp') should be of type number.
NOTE: I already know I can do as unknown as number but I shouldn't have to do such a thing.
Asked on github: https://github.com/sequelize/sequelize/issues/13522

Related

How can i solve this problem with typescript?

I have an interface in typescript to describe the data type of a structure. The problem is that when accessing this structure within an if, it gives me a typescript error that I don't understand and can't resolve. The code works.
This is the interface
interface ISignUpFormData {
username: {
value: string;
valid: boolean;
unique: boolean;
};
email: { value: string; valid: boolean; unique: boolean };
password: { value: string; valid: boolean };
birthdate: { value: string; valid: boolean };
}
And so I access the data
for (let data in formData) {
if (
formData[data].value === "" ||
!formData[data].valid ||
!formData[data].unique
) {
canContinue = false;
errors.push(data);
}
}
In the if condition lines I get this error:
The element implicitly has type "any" because the expression of type "string" cannot be used to index the type "ISignUpFormData".
No index signature with a parameter of type "string" was found on type "ISignUpFormData".

Mapping JSON object into Typed object with enum property

I am wanting to convert a JSON "string" that I pull from an api into my Typescript model, if i change one of the props from enum to string it works quite easily, however I cannot seem to map it to an enum despite hours of searching and trying different things.
I have a model that holds an array of types like this
export enum SEAT_TYPE {
ECONOMY = "ECONOMY",
PREMIUM_ECONOMY = "PREMIUM_ECONOMY",
BUSINESS = "BUSINESS",
}
export type Seat = {
number: string;
type: SEAT_TYPE;
status: boolean;
};
export class SeatingPlan {
seating: Seat[] = [];
}
I then pull something like this from an api
[{
number: "1A",
type: "BUSINESS",
status: false,
},
{
number: "1B",
type: "BUSINESS",
status: false,
},
{
number: "1C",
type: "BUSINESS",
status: false,
}]
An i'm using just a basic loop function to map over each element and convert it to a typed object like this
export function convert(json: Array<Seat>) {
return json.map(
(seat) =>
<Seat>{
number: seat.number,
type: seat.type as keyof typeof SEAT_TYPE,
status: seat.status,
},
);
}
But where i call my
convert(JSON)
I get this error and I'm totally lost at this point, i'm semi-new to typescript and i feel like i'm missing something quite simple, any help would be greatly appreciated.
Argument of type '{ number: string; type: string; status: boolean; }[]' is not assignable to parameter of type 'Seat[]'.
Type '{ number: string; type: string; status: boolean; }' is not assignable to type 'Seat'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'SEAT_TYPE'.
Thanks in advance.

Typescript error: type this is not assignable to type this

I am new to typescript and I am working on one project and I am trying to set up the project and I got an error from backend typescript I don't know how I solve it if someone knows that help me.
TS File
import { Document, Model, model, Schema } from "mongoose";
import { IUser } from "./GenUser";
/**
* Interface to model GenStatus for TypeScript.
* #param cStatusCode: string
* #param cStatusName: string
* #param cStatusDesc: string
* #param iEnteredby: string
* #param tEntered: Date
* #param iUpdatedby: string
* #param tUpdated: Date;
*/
export interface IStatus extends Document {
cStatusCode: string;
cStatusName: string;
cStatusDesc: string;
iEnteredby: IUser['_id'];
tEntered: Date;
iUpdatedby: IUser['_id'];
tUpdated: Date;
}
const GenStatus: Schema = new Schema({
cStatusCode: {
type: String,
required: true,
unique: true
},
cStatusName: {
type: String,
required: true,
unique: true
},
cStatusDesc: {
type: String,
required: true
},
iEnteredby: {
type: Schema.Types.ObjectId,
ref: "User"
},
tEntered: {
type: Date
},
iUpdatedby: {
type: Schema.Types.ObjectId,
ref: "User"
},
tUpdated: {
type: Date
}
});
const Status: Model<IStatus> = model("gen_Status", GenStatus);
export default Status;
Error
src/models/GenStatus.ts:55:7 - error TS2322: Type 'Model<Document<any, any, any>, any, any>' is not assignable to type 'Model<IStatus, {}, {}>'.
The types returned by 'create(...)' are incompatible between these types.
Type 'Promise<Document<any, any, any>[]>' is not assignable to type 'Promise<IStatus[]>'.
Type 'Document<any, any, any>[]' is not assignable to type 'IStatus[]'.
Type 'Document<any, any, any>' is not assignable to type 'IStatus'.
55 const Status: Model = model("gen_Status", GenStatus);
I resolve it and the answer is here.
Before
const Status: Model<IStatus> = model("gen_Status", GenStatus);
After
const Status: Model<IStatus> = model<IStatus>("gen_Status", GenStatus);

How to assign a sequelize Model to typed property

I explain i have this properties definition
export interface CrudOpts {
Model?: ModelCtor<Model>;
only?: string[];
except?: string[];
nestedRelations?: boolean;
basepath?: string;
}
when I use it in a decorator:
export function crud(opts: CrudOpts): Function {
return (target: any) => {
Reflect.defineMetadata('crud', opts, target.prototype);
}
}
and then here:
#crud({Model: Runner})
export class RunnerController {
}
I get this error
src/controllers/runner.controller.ts(6,8): error TS2322: Type 'typeof Runner' is not assignable to type 'ModelCtor<Model<any, any>>'.
Type 'typeof Runner' is not assignable to type 'typeof Model'.
Types of construct signatures are incompatible.
Type 'new (values?: RunnerCreateAttributes, options?: BuildOptions) => Runner' is not assignable to type 'abstract new <TModelAttributes extends {} = any, TCreationAttributes extends {} = TModelAttributes>(values?: TCreationAttributes, options?: BuildOptions) => Model<TModelAttributes, TCreationAttributes>'.
Types of parameters 'values' and 'values' are incompatible.
Type 'TCreationAttributes' is not assignable to type 'RunnerCreateAttributes'.
Type '{}' is not assignable to type 'Optional<RunnerAttributes, "id">'.
Type '{}' is not assignable to type 'Omit<RunnerAttributes, "id">'.
Type 'TCreationAttributes' is not assignable to type 'Omit<RunnerAttributes, "id">'.
Type '{}' is missing the following properties from type 'Omit<RunnerAttributes, "id">': email, avatar_url, firstname, lastname, and 14 more.
What I understand is that the Runner Model type can't be assigned to ModelCtor because of their type definitions but my question is how can I achieve this kind of thing to code cleanly with types ? does we have a type to assign models we defined to ?
here is my model definition:
class Runner extends Model<RunnerAttributes, RunnerCreateAttributes> {
public id!: number;
public email!: string;
public firstname!: string;
public lastname!: string;
public avatar_url!: string;
public timeto_id!: string;
public profile_type!: string;
public gender!: string;
public is_trial_registered!: boolean;
public is_anonyme!: boolean;
public birthdate!: string;
public bib!: number;
public sas!: string;
public subscription_date!: string;
public year_id!: number;
public group_id!: number;
public subgroup_id!: number;
public subgroupcompany_id!: number;
public roles!: string[]
}
Runner.init({
id: {
type: BIGINT,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
avatar_url: TEXT,
email: {
type: STRING,
allowNull: false,
},
firstname: STRING,
lastname: STRING,
timeto_id: {
type: STRING,
allowNull: false
},
profile_type: {
type: STRING,
allowNull: true,
defaultValue: 'public'
},
gender: STRING,
is_trial_registered: BOOLEAN,
is_anonyme: BOOLEAN,
birthdate: DATE,
bib: INTEGER,
sas: STRING,
subscription_date: DATE,
year_id: {
type: INTEGER,
allowNull: false
},
group_id: INTEGER,
subgroup_id: INTEGER,
subgroupcompany_id: INTEGER,
roles: {
type: ARRAY(STRING)
}
}, {
timestamps: false,
tableName: 'runner',
sequelize
})
export {Runner};
thanks in advance

Error in creating a custom validation using mongoose with typescript

import mongoose, { Schema, model } from "mongoose";
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, "Too few eggs"],
max: 12
},
bacon: {
type: Number,
required: [true, "Why no bacon?"]
},
drink: {
type: String,
enum: ["Coffee", "Tea"],
required: function() {
return this.bacon > 3;
}
}
});
The two errors that I get when I run this code are:
Property 'bacon' does not exist on type '{ type: StringConstructor;
enum: string[]; required: () => any; }'
'required' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
In order to type-check the required function, TypeScript needs to know what type of object this will refer to when required is called. By default, TypeScript guesses (incorrectly) that required will be called as a method of the containing object literal. Since Mongoose will actually call required with this set to a document of the structure you're defining, you'll need to define a TypeScript interface for that document type (if you don't already have one) and then specify a this parameter to the required function.
interface Breakfast {
eggs?: number;
bacon: number;
drink?: "Coffee" | "Tea";
}
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, "Too few eggs"],
max: 12
},
bacon: {
type: Number,
required: [true, "Why no bacon?"]
},
drink: {
type: String,
enum: ["Coffee", "Tea"],
required: function(this: Breakfast) {
return this.bacon > 3;
}
}
});
In my tscongig.json file inside compilerOptions, I changed the following and it worked:
"noImplicitThis": false,
...
/* Raise error on 'this' expressions with an implied 'any' type. */

Categories