我正在尝试使用 typescript 在 NodeJS 上创建 API
我有以下接口(interface):
export interface ISqlResonse<T> {
success?: string
error?: string
data: Array<T> //Nothing | array of object when are db operations
}
export interface IApiResponse<T> {
status: 'error' | 'success'
message: string
data: Array<T>
}
每个 api 调用都会调用一个函数,该函数调用通用类名 DB,从数据库中选择/插入/更新/删除数据 例如更新函数如下所示:
async updateData(input: IUpdateParam) : Promise<ISqlResonse<object>> {
...
...
}
API 函数调用 DB,如下所示:
async update(req): Promise<IApiResponse<IAccessPointsTableStructure>> {
let data = req.body ;
let updateObj = {
data ,
table: 'accessPoints',
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
let sqlResults = await db.updateData(updateObj) ; // !!!
if(typeof sqlResults.error==="string") {
logger.log('error','Error on updating Access Points!',{sql: db.getQuery(), error: sqlResults.error});
return({status:'error',message: 'Error on updating Access Points!',data: sqlResults.data});
}
logger.log('success', 'Access Points data updated with success!');
return({status: 'error', message: 'Access Points data updated with success!', data: sqlResults.data})
}
我的问题是:如何调用函数 db.updateData() 并告诉该函数我想从 ISqlResponse 接收数据,其中包含接口(interface) IAccessPointsTableStructure 等对象的数组。
换句话说,我想控制函数的返回类型。我用不同的方法测试了几次。 (替换 db.updateData(...) <..>... 中的机智 谢谢你的建议。
最佳答案
您尚未包含 IUpdateParam
的定义,但我假设它是 table
属性决定事物的类型 updateData()
返回。我在任何地方评论的“猜测”都只是举例;您应该更改它们以适合您的用例。
您应该能够修改 updateData()
的签名来反射(reflect)IUpdateParam
类型之间的关系传入的类型为Promise<ISqlResponse<{}>>
回。这是一种方法,使用 generics (您可以使用 overloads 代替)。首先,声明一个类型来表示每个表的表名和数据类型之间的映射。例如:
export type TableNameToTypeMapping = {
accessPoints: IAccessPointsTableStructure,
otherThings: IOtherThingsTableStructure, // guess
// ...
}
现在,您可以更改 IUpdateParam
的定义这样它只接受 table
的正确值:
export interface IUpdateParam<K extends keyof TableNameToTypeMapping> {
data: any, // guess
table: K,
excludeColumns: string, // guess
additionalColumns: any, // guess
validationRules: any, // guess
where: string // guess
}
所以IUpdateParam<'accessPoints'>
对象旨在处理 accessPoints
表,它与 IUpdateParam<'otherThings'>
不同对象。
现在是 updateData()
的签名可以改为:
async updateData<K extends keyof TableNameToTypeMapping>(
input: IUpdateParam<K>
): Promise<ISqlResonse<TableNameToTypeMapping[K]>> {
// implement this! The implementation is likely not
// type-safe unless you use runtime type guards
}
这意味着如果您调用 updateData
参数类型为IUpdateParam<'accessPoints'>
,您将得到 Promise<ISqlResponse<TableNameToTypeMapping['accessPoints']>>
。但是TableNameToTypeMapping['accessPoints']
只是 IAccessPointsTableStructure
,所以您将返回 Promise<ISqlResponse<IAccessPointsTableStructure>>
根据需要。
请注意,对象字面量 updateObj
将有其table
属性推断为类型 string
,太宽了。确保调用updateData()
按需要工作,您需要断言 updateObj.table
属性是文字类型 'accessPoints'
,像这样:
let updateObj = {
data,
table: 'accessPoints' as 'accessPoints', // assertion
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
或者您需要声明 updateObj
类型为IUpdateParam<'accessPoints'>
,像这样:
// type declaration
let updateObj:IUpdateParam<'accessPoints'> = {
data ,
table: 'accessPoints',
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
无论哪种方式都应该有效。
希望有帮助;祝你好运!
关于javascript - typescript 中具有动态返回的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46795568/