Description
Issue
Following methods do not accept an object with an association,
- Model.create()
Versions
"sequelize": "^6.37.6"
"sequelize-typescript": "^2.1.6"
My tsconfig has no strict mode settings enabled. Interestingly, this problem doesn't occur when strictNullChecks
is enabled. My tsconfig:
{
"compilerOptions": {
"outDir": "./dist",
"allowJs": true,
"module": "commonjs",
"target": "ES2020",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["./src/**/*"]
}
Explanation
I am using sequelize and typescript in a project. I am receiving an error when trying to create a new instance of a model while including one of its hasOne
associations. Relevant documentation on the matter: https://sequelize.org/docs/v6/advanced-association-concepts/creating-with-associations/.
// Model A
export class ModelA extends Model<
InferAttributes<ModelA>,
InferCreationAttributes<ModelA>
> {
// ... Other fields/columns, skipping for brevity
@HasOne(() => ModelB, { onDelete: "SET NULL" })
modelB: ModelB;
}
// Model B
export class ModelB extends Model<
InferAttributes<ModelB>,
InferCreationAttributes<ModelB>
> {
@BelongsTo(() => ModelA)
modelA?: ModelA;
}
And when I try to create an instance of ModelA, including ModelB:
await ModelA.create({...propertiesOfModelA,
modelB: {...propertiesOfModelB}},
{include: [ModelB],})
I am met with this error:
Type '<fields of modelB argument>' is missing the following properties from type 'ModelB': $add, $set, and 35 more.ts(2740)
ModelA(90, 3): The expected type comes from property 'modelB' which is declared here on type 'Optional<InferCreationAttributes<ModelA, { omit: never; }>, NullishPropertiesOf<InferCreationAttributes<ModelA, { omit: never; }>>>'
I do not expect typescript to enforce that the modelB
field in the values
argument contain every single field, property, and method of an instance of ModelB
. I can remove the stricter typing like this:
export class ModelA extends Model {}
But then Typescript has no way to enforce the types inside of the values
argument passed into the create
method.
I could typecast, but this feels like a bandaid:
await ModelA.create({...propertiesOfModelA, modelB: {...propertiesOfModelB} as ModelB,
{include: [ModelB],})
I could also define the type of ModelA
's modelB
field as partial, but this incorrectly communicates that all fields and columns in ModelB
are optional (even if some are specified as required/not nullable).
@HasOne(() => ModelB, {onDelete: "SET NULL"})
modelB: Partial<ModelB>
Even if I were to define ModelB as such, the error persists:
export class ModelB extends Model<Partial<ModelB>> {}
My goal is to maintain type strictness in all relevant model methods (specifically create), so that I can still create models with associations and ensure I'm passing in the correct types.