class User extends Model双泛型参数写法含义解析
class User extends Model<UserAttribute, UserCreationAttribute> 代码含义说明 这段是TypeScript环境下使用Sequelize ORM定义数据模型的标准写法,核心作用是给Sequelize的基础Model类传入类型参数,实现从数据查询到数据创建全流程的类型校验。
两个泛型参数的具体作用
UserAttribute:对应数据库中查询返回的完整用户记录类型,包含表中所有字段,比如自增主键ID、数据库自动生成的创建时间、更新时间这类不需要用户手动传入的字段。UserCreationAttribute:对应创建新记录时允许传入的字段类型,你提到的用Omit从UserAttribute中省略部分字段是最常见的写法——省略的通常就是数据库会自动填充、不需要用户手动传值的字段。
为什么需要同时传入两个泛型
很多人会疑惑既然创建类型是从完整记录类型派生的,为什么ORM不自动推导,非要显式传第二个参数?核心原因很简单:
Sequelize作为通用ORM,根本没法预判你每张表里哪些字段是自动生成的。不同表的自动字段规则完全不一样:有的表主键是自增
id,有的是自定义的snowflake_id;有的表开了软删除、自动更新时间,有的表没有这些字段。没有办法在基类里写死统一的Omit规则,所以必须把创建时的类型显式传进去。
这种写法的实际效果
传对两个泛型之后,你在写业务代码的时候TS会自动做两层校验:
- 查询操作:
findOne、findAll返回的用户实例,所有字段(包括自动生成的id、时间字段)都会有正确的类型提示,不会出现TS识别不到属性的报错。 - 创建操作:调用
create、build方法时,TS会自动校验你传入的参数:少传必填字段、手动传入不允许赋值的自动生成字段(比如手动给自增id传值),都会在编译阶段直接报错,提前拦截低级错误。
举个最常见的使用示例:
// 完整表字段类型 interface UserAttribute { id: number; username: string; passwordHash: string; createdAt: Date; } // 创建时不需要传id和createdAt,数据库会自动生成 type UserCreationAttribute = Omit<UserAttribute, 'id' | 'createdAt'> // 定义User模型 class User extends Model<UserAttribute, UserCreationAttribute> {} // 校验通过:创建时只传需要手动赋值的字段 await User.create({ username: "zhangsan", passwordHash: "xxxxxx" }) // 类型报错:id是自动生成字段,不允许手动传入 await User.create({ id: 1, username: "zhangsan", passwordHash: "xxxxxx" }) // 类型正常:查询返回的实例可以直接读取自动生成的id字段 const user = await User.findOne({ where: { username: "zhangsan" } }) console.log(user?.id)
内容的提问来源于stack exchange,提问作者Rishabh Mishra
相关产品推荐
相关产品推荐

