这是我第一次遇到这个问题,如果标题没有意义,我很抱歉,我想不出一个好的方式来表达。
我正在使用一个返回如下响应的API:
{
PaginatedResults: {
TotalResults: 100,
Offset: 0,
Limit: 0,
PageSize: 100,
},
Error: {
Message: '',
Code: '',
},
Customers: [{...}]
}
其中Customers
可以替换为API可能返回的任何类型。所以它也可以像这样:
{
PaginatedResults: {
TotalResults: 100,
Offset: 0,
Limit: 0,
PageSize: 100,
},
Error: {
Message: '',
Code: '',
},
Sales: [{...}]
}
我现在这样表示类型:
type PaginatedResponse<TResponse extends object> =
TResponse &
Readonly<{
PaginatedResponse: {
TotalResults: number;
Offset: number;
Limit: number;
PageSize: number;
};
Error?: {
Message: string;
Code: string;
};
}>;
这一直工作得很好,但我最近遇到了一个问题,当我试图创建一个通用的辅助函数来自动分页端点。
为了跟踪所有的结果,我需要做这样的事情:
const allResults = [...initialResults];
const nextResp = await apiCall();
allResults.push(...nextResp['Customers'])
但问题是密钥'Customers'
可以是API可能返回的50多种类型中的任何一种。我需要一种通用的方式来索引响应。我已经尝试了很多不同的事情,但都没有成功,所以我希望得到一些关于处理这种事情的最佳方法的指导。
单独使用TypeScript在这里不会有太大帮助。在...nextResponse['Customers']
中,您期望TypeScript填写正确的密钥。但是正确的键是什么只能在运行时或者由手动提供的泛型类型知道。
但也许这对你有帮助:
// I added some generic types here which will help later
type PaginatedResponse<TResponse extends {[key in TKey]: any}, TKey extends keyof TResponse = keyof TResponse> =
Readonly<{
PaginatedResponse: {
TotalResults: number,
Offset: number,
Limit: number,
PageSize: number,
};
Error?: {
Message: string;
Code: string;
};
}> & TResponse
定义可能的Response
类型:
type Response1 = PaginatedResponse<{Customers: any}>
type Response2 = PaginatedResponse<{Sales: any}>
type AllResponses = Response1 | Response2
现在让我们定义一个函数,该函数获取PaginatedResponse
并将TResponse
压入数组:
type GetResponseKey<T> = T extends PaginatedResponse<infer TRes, infer TKey> ? TKey : never
const arr: any[] = []
function pushToResponseArray<
T extends AllResponses,
K extends GetResponseKey<T>
>(response: T, key: K){
arr.push(response[key])
}
const res: Response1 = {} as any
pushToResponseArray(res, "Customers") // We have to manually specify the key here
// but typescript will check if key is correct
这不是一个完美的解决方案,我认为你总是必须手动设置key
或确定它与一些JavaScript逻辑。
总结一下:
在应用程序的某个地方,您需要一些JavaScript逻辑来确定PaginatedResponse
的类型。然后将该类型映射到相应的键来访问TResponse
。
沙箱