Vue3组合API中如何包装Promise并保留原函数返回类型?
问题:让useForm的makeRequest返回与传入请求函数一致的类型
我有一个基于Axios实例的register函数,类型定义如下:
async function register(data: RegisterData): Promise<AxiosResponse<UserResponse, any>>
实现代码:
export const register = (data: RegisterData) => api.post<UserResponse>('register', data)
我用Vue3组合API封装了表单逻辑useForm函数,接收表单初始值和请求函数(比如register):
import {reactive, ref} from 'vue' import Errors from '../helpers/Errors' import type {AxiosResponse} from 'axios' export function useForm<T extends Record<string, any>, R extends (...args: any) => Promise<AxiosResponse>>(init: T, request: R) { const form = reactive<T>(init) const errors = reactive(new Errors()) const isLoading = ref(false) const makeRequest = () => { isLoading.value = true errors.clear() return request(form) .then(response => Promise.resolve(response)) .catch(e => { if (e.response.status === 422) { errors.save(e.response.data.errors) } return Promise.reject(e) }) .finally(() => isLoading.value = false) } return {form, errors, isLoading, makeRequest} }
在RegisterPage.vue中调用时:
import {useForm} from '../../../composables/form' import {register} from '../../../api/auth' const {form, isLoading, errors, makeRequest} = useForm({ username: null, password: null, password_confirmation: null, referral_code: null }, register) makeRequest() // 当前返回类型:Promise<AxiosResponse<any, any>>,期望返回:Promise<AxiosResponse<UserResponse, any>>
如何让makeRequest的返回类型与传入的请求函数(如register)完全一致?
解决方案
问题出在useForm的泛型定义上:原代码中R的返回类型Promise<AxiosResponse>没有保留具体的泛型参数(即UserResponse和错误类型),导致TypeScript无法推断出准确的返回类型。
修改useForm的泛型定义,明确请求函数的参数类型和返回类型的泛型信息,就能让makeRequest继承传入请求函数的完整类型:
import {reactive, ref} from 'vue' import Errors from '../helpers/Errors' import type {AxiosResponse} from 'axios' // 重新定义泛型参数,明确表单数据、响应数据、错误数据的类型 export function useForm< FormData extends Record<string, any>, ResponseData, ErrorData = any >( init: FormData, request: (data: FormData) => Promise<AxiosResponse<ResponseData, ErrorData>> ) { const form = reactive<FormData>(init) const errors = reactive(new Errors()) const isLoading = ref(false) // 明确makeRequest的返回类型与请求函数一致 const makeRequest = (): Promise<AxiosResponse<ResponseData, ErrorData>> => { isLoading.value = true errors.clear() return request(form) .then(response => response) // 无需额外Promise.resolve,直接返回即可 .catch(e => { // 增加可选链避免e.response为undefined时报错 if (e.response?.status === 422) { errors.save(e.response.data.errors) } return Promise.reject(e) }) .finally(() => isLoading.value = false) } return {form, errors, isLoading, makeRequest} }
关键修改点:
- 泛型参数细化:新增
ResponseData和ErrorData泛型,让请求函数的返回类型携带具体的响应和错误类型信息。 - 请求函数类型约束:明确
request参数必须接收FormData类型的参数,返回带有具体泛型的AxiosResponse。 - 明确makeRequest返回类型:直接指定其返回类型与
request的返回类型一致,TypeScript会自动推断ResponseData和ErrorData的具体类型(比如传入register时,ResponseData会被推断为UserResponse)。
修改后,调用makeRequest()时,返回类型会自动匹配register的Promise<AxiosResponse<UserResponse, any>>,符合预期。
内容的提问来源于stack exchange,提问作者Seagle
相关产品推荐
相关产品推荐

