简体   繁体   English

在打字稿中具有动态返回的功能

[英]Function with dynamic return in typescript

I am trying to create an API on NodeJS with typescript 我正在尝试使用typescript在NodeJS上创建一个API

I have the following interfaces : 我有以下接口:

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>
}

Each api call call a function that call an generic class name DB that select/insert/update/delate data from an database For example the update function look like : 每个api调用都调用一个函数,该函数调用泛型类名称DB,该类从数据库中选择/插入/更新/删除数据。例如,更新函数如下所示:

 async updateData(input: IUpdateParam) : Promise<ISqlResonse<object>> {
    ...
    ...
}

API function call DB and look like : 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})
}

My question is : how can I call the function db.updateData() and tell this function that I want to receive in data from ISqlResponse an array with objects like interface IAccessPointsTableStructure. 我的问题是:如何调用函数db.updateData()并告诉该函数我要从ISqlResponse接收数据,该数组包含对象IAccessPointsTableStructure等对象。

With other words i want to control the returning type of function. 换句话说,我想控制函数的返回类型。 I teste several times with different approaches . 我用不同的方法测试了几次。 (Replace wit in db.updateData(...) <..>... Thank you in advice. (在db.updateData(...)<..> ...中替换机智。谢谢您的建议。

You haven't included the definition of IUpdateParam , but I will assume that its table property is what decides the type of thing updateData() returns. 您尚未包括IUpdateParam的定义,但我将假定它的table属性决定了updateData()返回的事物的类型。 Everywhere I've commented "guess" is just for example; 我评论过“猜猜”的每个地方都只是举例。 you should change them to fit your use cases. 您应该更改它们以适合您的用例。


You should be able to modify the signature for the updateData() to reflect the relationship between the type of IUpdateParam passed in and the type of Promise<ISqlResponse<{}>> returned. 您应该能够修改updateData()的签名,以反映传入的IUpdateParam类型与返回的Promise<ISqlResponse<{}>>类型之间的关系。 Here's one way to do it, using generics (you could use overloads instead). 这是使用泛型的一种方法(您可以改用重载 )。 First, declare a type to represent the mapping between the table names and the data type for each table. 首先,声明一个类型,以表示表名和每个表的数据类型之间的映射。 For example: 例如:

export type TableNameToTypeMapping = {
  accessPoints: IAccessPointsTableStructure,
  otherThings: IOtherThingsTableStructure, // guess
  // ...
}

Now, you can change the definition of IUpdateParam so that it only accepts the right values for table : 现在,您可以更改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
}

So an IUpdateParam<'accessPoints'> object is meant to deal with the accessPoints table, and it is different from an IUpdateParam<'otherThings'> object. 因此, IUpdateParam<'accessPoints'>对象用于处理accessPoints表,它与IUpdateParam<'otherThings'>对象不同。

Now the signature for updateData() can be changed to: 现在,可以将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
  }

This means if you call updateData with a parameter of type IUpdateParam<'accessPoints'> , you will get back a Promise<ISqlResponse<TableNameToTypeMapping['accessPoints']>> . 这意味着,如果使用类型为IUpdateParam<'accessPoints'>的参数调用updateData ,将返回Promise<ISqlResponse<TableNameToTypeMapping['accessPoints']>> But TableNameToTypeMapping['accessPoints'] is just IAccessPointsTableStructure , so you are getting back a Promise<ISqlResponse<IAccessPointsTableStructure>> as desired. 但是TableNameToTypeMapping['accessPoints']只是IAccessPointsTableStructure ,因此您可以根据需要返回Promise<ISqlResponse<IAccessPointsTableStructure>>


Note that the object literal updateObj will have its table property inferred as type string , which is too wide. 请注意,对象文字updateObj将其table属性推断为string类型,该属性太宽。 To make sure the call to updateData() works as desired, you will either need to assert that the updateObj.table property is of literal type 'accessPoints' , like this: 为了确保对updateData()的调用能够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
}

or you will need to declare that updateObj is of type IUpdateParam<'accessPoints'> , like this: 否则,您需要声明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
}

Either way should work. 两种方法都应该起作用。


Hope that helps; 希望能有所帮助; good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM