You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缩短TypeScript+Sequelize场景下标志位虚拟字段泛型调用

解决方案

核心优化思路

  • 利用TS的this参数约束函数运行时的上下文类型,不需要把模型相关类型作为泛型传入,直接砍掉3个冗余泛型参数
  • 提前约束使用该函数的模型必须包含number类型的flags字段,让TS可以正确推导getDataValue的入参合法性和返回值类型
  • 仅保留标志位配置的泛型参数,自动约束第二个入参为标志位类型的合法key

完整实现代码

基础类型与工具函数定义

import { Model, DataTypes } from 'sequelize-typescript';

// 约束所有使用标志位的模型必须包含number类型的flags字段
type FlagModel = Model & { flags: number };

// 仅需要传入标志位配置的泛型T
function createFlagVirtual<T extends Record<string, number>>(
  flagPositions: T,
  flagKey: keyof T
) {
  return {
    type: DataTypes.BOOLEAN,
    get(this: FlagModel) {
      // 两种写法TS都可以正确识别类型
      const flags = this.getDataValue('flags');
      // 也可以直接写 const flags = this.flags;
      return !!(flags & (1 << flagPositions[flagKey]));
    },
    set(this: FlagModel, value: boolean) {
      const flags = this.getDataValue('flags');
      const mask = 1 << flagPositions[flagKey];
      this.setDataValue('flags', value ? flags | mask : flags & ~mask);
    }
  }
}

业务侧使用示例

// 定义你的标志位配置
interface IUserFlags {
  isDev: number;
  isAdmin: number;
  isMod: number;
}
const UserFlags: IUserFlags = {
  isDev: 0,
  isAdmin: 1,
  isMod: 2
}

// 在User模型里使用,仅需要传IUserFlags一个泛型参数
@Table
class User extends Model<IUserAttributes, IUserCreationAttributes> {
  @Column(DataTypes.INTEGER)
  flags: number;

  // 虚拟字段定义,TS会自动校验第二个参数是IUserFlags的合法key
  @Column(createFlagVirtual<IUserFlags>(UserFlags, 'isDev'))
  isDev: boolean;

  @Column(createFlagVirtual<IUserFlags>(UserFlags, 'isAdmin'))
  isAdmin: boolean;

  @Column(createFlagVirtual<IUserFlags>(UserFlags, 'isMod'))
  isMod: boolean;
}

类型校验说明

  • 调用时仅需要传入IUserFlags一个泛型,第二个参数会自动触发TS类型提示,传入不在IUserFlags定义内的key会直接报错
  • this.getDataValue('flags')会被TS识别为合法调用,返回值自动推导为number类型,和直接访问this.flags效果完全一致

内容的提问来源于stack exchange,提问作者user16238654

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 03:15:03