我正在尝试使用Axios在Typescript中为我的API实现一个通用的CRUD接口。
假设API公开了用于对2个实体执行CRUD操作的端点。假设端点是/users
和/posts/
,并且这两个端点都采用offset
和count
参数(用于分页)。响应示例:
GET /users?offset=2&count=2
{
"users": ["user1", "user2"],
"total": 4 // the total number of users that exist
}
与此类似,对于posts
,帖子数组的关键字是`“post”。
我尝试创建一个通用函数来获取用户/帖子,如下所示:
export const getPage =
async <T extends Persistable>(offset: number, count: number): Promise<PaginatedResponse<T>> => {
const response = await axios.get<PaginatedResponse<T>>(
`${SOME_URL}/<BLANK>`,
{
params: { page, size },
transformResponse: [
(data) => ({
...data,
items: data[<BLANK>],
})
]
},
);
return response.data;
};
其中,User
和Post
接口均继承的Persistable
接口和PaginatedResponse
接口如下所示:
export interface PaginatedResponse<T> {
readonly total: number;
readonly items: T[];
}
基本上,我需要填充<BLANK>
,例如,根据传递的类型T
,以某种方式分别获取字符串"users"
/"posts"
。
有人能想出一种方法来实现这一点吗?
发布于 2019-07-24 11:41:21
我可能会建议以下使用函数重载的解决方案。在这种情况下,我不会使用泛型重新注释,因为T
仅限于user
或post
。由于TypeScript接口与形状有关,因此通过泛型,T
实际上可以是任何扩展Persistable
的东西
我曾设想用户和帖子将不是字符串数组,而是对象数组。type
属性将创建discriminated union,并将在编译后保留。
我已经向getPage
函数添加了额外的参数reqType
来区分用户和posts请求。reqType
可以是'user'
或'post'
。其他值将导致错误。
此User['type']
为indexed access operator,因此如果您将来要添加另一种类型的响应,reqType将自动填充type
值。
type User = { type: 'user', user: string };
type Post = { type: 'post', post: string };
export interface PaginatedResponse<T> {
readonly total: number;
readonly items: T[];
}
// This is type guard which will stay in run time
function reqTypeIsUser(a: User['type'] | Post['type']): a is User['type'] {
return (a as User['type']) === 'user'
}
async function getPage
(offset: number, count: number, reqType: User['type']): Promise<PaginatedResponse<User>>
async function getPage
(offset: number, count: number, reqType: Post['type']): Promise<PaginatedResponse<Post>>
async function getPage
(offset: number, count: number, reqType: User['type'] | Post['type']): Promise<PaginatedResponse<User | Post>> {
const response = await axios.get<PaginatedResponse<User | Post>>(
'url' + reqTypeIsUser(reqType) ? 'users' : 'posts',
{
params: { offset, count },
transformResponse: [
(data) => ({
...data,
items: data[reqType].map((d: string) => ({ type: reqType, [reqType]: d })),
})
]
},
);
return response.data;
};
let user = getPage(1, 2, "user"); // user will be Promise<PaginatedResponse<User>>
https://stackoverflow.com/questions/57181194
复制