我正在将Sequelize与一些第三方库生成的接口用于我的各种表,以使Sequelize在TypeScript应用程序中确实能很好地工作。
Sequelize提供了一个接口Instance<A>
,它表示对SELECT ... LIMIT 1
查询的查找结果。它具有该行的所有列以及各种帮助程序,如toJSON(),该方法仅返回没有帮助程序的列的JSON表示形式。
我的3PL生成的接口代表我所有表的实例以及我所有表的属性,以及一堆我省略的好东西。
在我的代码中,我想运行Sequelize查询(返回一个Promise<Instance<A>>
),然后调用toJSON()
函数,以便我的数据服务返回数据的JSON表示,而没有诸如toJSON
(这样我就可以序列化数据并通过HTTP发送)。实际上,返回attributes
(仅是列数据)而不是instance
(列数据以及各种不可序列化的内容,例如方法和循环数据)。
我想创建一个接受实例并返回属性的函数extractData: (Instance<A>) => A
,以便可以执行query().then(extractData)
而不是query().then(result => result.toJSON())
。这是为了提高可读性。
但是,我的extractData
函数Argument of type '<A>(data:Instance<A>)=>A' is not assignable to parameter of type '(a:tableInstance)=>tableAttribute'. Types of parameter 'data' and 'a' are incompatible. Types of property 'Model' are incompatible. /*snip*/ 'this' could be instantiated with an arbitrary type which could be unrelated to 'tableInstance'
遇到错误。
我不明白他们在说什么不兼容的类型。此外,如果我编写的辅助接口是Instance
的简化形式,称为$Instance
,仅具有toJSON
方法,然后在我的extractData
函数中使用该接口,错误消失了。为什么?
在SO上还有许多与此问题类似的问题,但是它们的变化都稍有不同,例如人们将泛型与类名混淆(我在这里没有做过)。我找不到一个合适的答案(实际上,我花了二十分钟通过许多问题,然后花三十分钟来撰写自己的问题;找到一个已经回答的问题比写这个问题要快得多)。
(我也可以尝试query().then(extractData.bind(extractData))
来使错误消失,但是TypeScript将返回值检测为unknown
而不是tableAttribute
。)
有关我所讨论内容的简化代码,请参见下文:
// simplified for this SO post from Sequelize types 3.30.4
interface Model<I, A> /*extends some interfaces*/ {
/* some props, methods */
}
interface Instance<A> {
Model: Model<this, A>
toJSON(): A
}
// 3PL-generated sequelize typescript interfaces/types
interface tableAttribute { /* models SQL table */
id: number
foo: string
bar: string
}
interface tableInstance extends Instance<tableAttribute>, tableAttribute { }
// My code
interface $Instance<A> {
toJSON(): A
}
const extractData = <A>(data: Instance<A>) => data.toJSON() // Instance<A> => A
const $extractData = <A>(data: $Instance<A>) => data.toJSON() // $Instance<A> => A
declare const getData: () => Promise<tableInstance>
const fetch = () => getData().then(extractData) // ERROR!
const $fetch = () => getData().then($extractData) // () => Promise<tableAttribute>