Typescript與orm框架sequelize語法衝突的問題

      如果不想在nodejs中大量的手寫sql,就可以採用orm框架sequelize,它非常類似於Java的JPA,讓你的代碼看起來更規範簡潔高效。不過在採用sequelize編寫的過程中遇到了一些問題,而網上的資料又太少;不是沒有去sequelize官網看過,主要是官網的API示例都是針對一般的js語法,而我的項目使用了TypeScript,有好多地方功能雖然可以正常執行,但是代碼下面會冒紅(紅顏色波浪線),鼠標放上去提示:TS2322:the type xxx is not assign to xxxxx。這種屬於語法問題,typescript要求的比較嚴格。

     下面來看一個例子,API爲findOrCreate,意思是根據條件查找,如果找到就返回,沒找到則創建一條。在對實體類進行jpa操作時,首先用sequelize定義字段類型與數據庫字段的映射,例如:

export const StudentModel = sequelize.define('student', {
    id: {
        type: Sequelize.BIGINT,
        field: 'id',
        primaryKey: true,
        autoIncrement: true
    },
    name: {
        type: Sequelize.STRING,
        field: 'name'
    },
    age: {
        type: Sequelize.TINYINT,
        field: 'age'
    },
    tel: {
        type: Sequelize.STRING,
        field: 'tel'
    },
    createTime: {
        type: Sequelize.BIGINT,
        field: 'create_time'
    },
    updateTime: {
        type: Sequelize.BIGINT,
        field: 'update_time'
    }
}, {
    timestamps: false,
    tableName: 'student'
});

     按照官網 findOrCreate的用法,根據where條件後面的選項來查找記錄,如果沒找到,則將where裏面的條件和defaults裏面的屬性一起作爲待插入項,所以我只需要像如下這麼寫:

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {
            age: `${age}`,
            createTime: `${time}`,
            updateTime: `${time}`}
    });

      事實是運行功能執行正常,但是由於採用了TypeScript來編寫,“defaults”那裏此時會冒紅,而且持續集成的編譯不會通過,鼠標放在defaults上會提示TS2322: type 'xxxx' is not assignable to  type 'xxxx'。意思是類型對應不上,要求你defaults裏面的參數必須和StudentModel裏面定義的完全一致,少一個都不行,我不知道爲什麼會這樣,難道sequelize沒有對typescript做優化嗎?defaults裏面如果把所有參數都填上,怪怪的,我id是自增的,肯定不能給id默認值,所以賦給null,where條件裏面已經填了兩個參數還要再填一遍,沒辦法先編譯通過再說,改正後如下:

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {id:null,
            name: `${name}`,
            tel: `${tel}`,
            age: `${age}`,
            createTime: `${time}`,
            updateTime: `${time}`}
    });

      再來說第二個問題:sequelize的api有一個回調方法,有的是then,有的是spread,這裏根據官網文檔使用spread將結果切分爲倆個部分,一個是返回的實例對象,一個是行爲布爾值,我是這麼理解的。

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {id:null,
            name: `${name}`,
            tel: `${tel}`,
            age: 21,
            createTime: `${time}`,
            updateTime: `${time}`}
    })
    .spread((student, created) => {
        // 如果找到則直接更新,沒找到會自動創建
        if (created === false) {
            (async () => {
                await StudentModel.update(
                    {age: 22, updateTime: `${time}`},
                    {where: {id: student.id}});
            })();
        }
    });

     此處不管是找到也好,創建的也好,spread第一個參數返回的都是student對象,然後緊接着我會用到student對象的屬性id值,本地執行也是正常的,但就是在student.id那裏冒紅 ,也是報TS2322啥的,意思是說student是object類型的無法點出id屬性。後來問了web前端工程師,他說要對spread的第一個參數student加個類型,要加類型就要先定義類型,這樣寫:

interface Student {
    id:number;
    name?:string;
    ...
    ...
}

    定義好以後 ,對spread的第一個參數student加個類型,如下所示

.spread((student: Student, created) => { 

    當然了,如果你嫌麻煩,也可以直接將其定義爲any類型,對象依然是原來的那個對象,只是讓typescript不再報語法錯誤

.spread((student: any, created) => { 

    這次student.id不再冒紅了。我說我已經定義了一個StudentModel,這裏的類型換成StudentModel怎麼也冒紅,他說typescript裏面有專門定義自己屬性的接口,不能混淆。

    其實sequelize還有一個叫upsert的API,是updateOrInsert的簡稱,where條件裏面必須包含能定爲一條記錄的唯一索引,否則無效,就拿上面的例子來說,如果你能獲取到id值,則上面的寫法可以換成upsert一個api就夠了,很精簡。

    最後如果使用了sequelize後,啓動時控制檯報這個錯

sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at

   此時可以這麼做,修改你的sequelize.ts文件,重點在於operatorsAliases這一大堆:

const Op = Sequelize.Op;
export const sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.password, {
  host: dbConfig.host,
  port: dbConfig.port,
  dialect: 'mysql',
  operatorsAliases: {
      $eq: Op.eq,
      $ne: Op.ne,
      $gte: Op.gte,
      $gt: Op.gt,
      $lte: Op.lte,
      $lt: Op.lt,
      $not: Op.not,
      $in: Op.in,
      $notIn: Op.notIn,
      $is: Op.is,
      $like: Op.like,
      $notLike: Op.notLike,
      $iLike: Op.iLike,
      $notILike: Op.notILike,
      $regexp: Op.regexp,
      $notRegexp: Op.notRegexp,
      $iRegexp: Op.iRegexp,
      $notIRegexp: Op.notIRegexp,
      $between: Op.between,
      $notBetween: Op.notBetween,
      $overlap: Op.overlap,
      $contains: Op.contains,
      $contained: Op.contained,
      $adjacent: Op.adjacent,
      $strictLeft: Op.strictLeft,
      $strictRight: Op.strictRight,
      $noExtendRight: Op.noExtendRight,
      $noExtendLeft: Op.noExtendLeft,
      $and: Op.and,
      $or: Op.or,
      $any: Op.any,
      $all: Op.all,
      $values: Op.values,
      $col: Op.col
  },
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  },
});

  參考https://stackoverflow.com/questions/46608382/sequelize-deprecated-error-message 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章