Home > Back-end >  how to wrap a promise and keep the return type?
how to wrap a promise and keep the return type?

Time:07-16

I have a function that uses an axios instance and has type async function register(data: RegisterData): Promise<AxiosResponse<UserResponse, any>>

export const register = (data: RegisterData) => api.post<UserResponse>('register', data)

Using the vue 3 composition api I am trying to create a wrapper over the form logic. The request parameter accepts a register function (or other similar functions).

form.ts

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() // returns value of Promise<AxiosResponse<any, any>> type
// ...

But when I call the wrapper function, it returns the following type Promise<AxiosResponse<any, any>>

How can I make the makeRequest function return the same type as the register function (Promise<AxiosResponse<UserResponse, any>>)?

CodePudding user response:

You can use a type assertion for the makeRequest function.

export function useForm<
  T extends Record<string, any>, 
  R extends (...args: any) => Promise<AxiosResponse>
>(init: T, request: R) {

  /* ... */  

  const makeRequest = (() => {
    /* ... */
  }) as () => ReturnType<R>

  /* ... */
}

Now the returned makeRequest function will have the correct type.

const {form, isLoading, errors, makeRequest} = useForm({
  username: null,
  password: null,
  password_confirmation: null,
  referral_code: null
}, register)

const result = makeRequest()
//     ^? const result: Promise<AxiosResponse<UserResponse, any>>

Playground

  • Related