javascript - typescript 中具有动态返回的函数

标签 javascript node.js typescript

我正在尝试使用 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/

相关文章:

javascript - ChartJS : Draw vertical line at data point on chart on mouseover

javascript - 如何在 Winjs、Windows 应用商店应用程序中运行 C# 作为后台

javascript - 为什么 Node fs.watchFile 使测试无法完成?

typescript - NestJS 中的 Shopify Webhook

javascript - 如何在 ChromeWorker 中使用事件?

Javascript 将字符串动态附加到脚本元素

javascript - 如何在 ES6 中将一个 JS 文件导入另一个 JS 文件?

node.js - 下面的 Mongoose 查询中的第三个参数有什么作用?

reactjs - 在 React 组件上使用 TypeScript 进行函数重载?

typescript - 为什么 getter/setter 在 vue typescript 类组件中无法正常工作