diff --git a/.changeset/sequelize-declare-attributes.md b/.changeset/sequelize-declare-attributes.md new file mode 100644 index 0000000..d5de7f2 --- /dev/null +++ b/.changeset/sequelize-declare-attributes.md @@ -0,0 +1,20 @@ +--- +"seamless-templates": patch +--- + +fix(templates): declare Sequelize model attributes instead of using public class fields + +The `User` model in both API starters (`express` and `fastify`) declared its +attributes as `public id!: string`. Sequelize installs its attribute getters and +setters on the prototype, and a public class field is emitted as an own property +initialised to undefined, which shadows them: `user.id` reads undefined while +`user.get("id")` returns the row's value. Sequelize warns about this at model +init. `declare` emits no field at all, so the accessors survive. + +Whether the field is emitted depends on `useDefineForClassFields`, which follows +`target`. Both starters compile at `target: ES2020`, where the field is erased +and the shadowing does not occur, so this is a guard rather than a repair of +behaviour anyone is seeing today. It matters because the guard is what keeps a +later `target` bump from silently breaking every model: at ES2022 the same code +returns undefined for every attribute, and the first symptom is a query built +with an undefined parameter on a handler that filters by `req.appUser.id`. diff --git a/templates/api/express/models/user.ts b/templates/api/express/models/user.ts index 425901d..e4ec9e0 100644 --- a/templates/api/express/models/user.ts +++ b/templates/api/express/models/user.ts @@ -10,11 +10,11 @@ export interface UserAttributes { } export class User extends Model implements UserAttributes { - public id!: string; - public email!: string | null; - public phone!: string | null; - public readonly created_at!: Date; - public readonly updated_at!: Date; + declare id: string; + declare email: string | null; + declare phone: string | null; + declare readonly created_at: Date; + declare readonly updated_at: Date; } const initializeUserModel = (sequelize: Sequelize) => { diff --git a/templates/api/fastify/models/user.ts b/templates/api/fastify/models/user.ts index 425901d..e4ec9e0 100644 --- a/templates/api/fastify/models/user.ts +++ b/templates/api/fastify/models/user.ts @@ -10,11 +10,11 @@ export interface UserAttributes { } export class User extends Model implements UserAttributes { - public id!: string; - public email!: string | null; - public phone!: string | null; - public readonly created_at!: Date; - public readonly updated_at!: Date; + declare id: string; + declare email: string | null; + declare phone: string | null; + declare readonly created_at: Date; + declare readonly updated_at: Date; } const initializeUserModel = (sequelize: Sequelize) => {