I am trying to add typescript to my current project, so after using it with Axios post request, I am facing an issue.
Use case is that I want to send email firstname lastname and password in my post request and in response I want to get accessToken
Here is the code below:
export interface UserRegistrationModel {
email: string;
password: string;
firstname: string;
lastname: string;
}
export const register = async (user: UserRegistrationModel) => {
const { data } = await http.post<UserRegistrationModel>("/users", user);
return data;
};
This is my function called after I submit the registration form like:
register(values)
.then((data) => {
console.log(data.accessToken);
setLoading(false);
}).catch(() => {
setLoading(false);
});
So here in my then block when I try to access accessToken by data.acessToken throws error.
Property 'accessToken' does not exist on type 'UserRegistrationModel'
So I tried to define a new Interface named AuthModel but then when I assign it to data like:
export interface AuthModel {
accessToken: string
}
register(values)
.then((data:AuthModel) => {
console.log(data.accessToken);
setLoading(false);
}).catch(() => {
setLoading(false);
setSubmitting(false);
setStatus("Registration process has broken");
});
It says:
Argument of type '(data: AuthModel) => void' is not assignable to parameter of type '(value: UserRegistrationModel) => void | PromiseLike'. Types of parameters 'data' and 'value' are incompatible. Property 'accessToken' is missing in type 'UserRegistrationModel' but required in type 'AuthModel'.
Below is the axios config in anyone wants to see:
http.ts:
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
enum StatusCode {
Unauthorized = 401,
Forbidden = 403,
TooManyRequests = 429,
InternalServerError = 500,
}
const headers: Readonly<Record<string, string | boolean>> = {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Credentials": true,
"X-Requested-With": "XMLHttpRequest",
};
// We can use the following function to inject the JWT token through an interceptor
// We get the `accessToken` from the localStorage that we set when we authenticate
const injectToken = (config: AxiosRequestConfig): AxiosRequestConfig => {
try {
const token = localStorage.getItem("accessToken");
if (token != null) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
} catch (error: any) {
throw new Error(error);
}
};
class Http {
private instance: AxiosInstance | null = null;
private get http(): AxiosInstance {
return this.instance != null ? this.instance : this.initHttp();
}
initHttp() {
const http = axios.create({
baseURL: "https://api.example.com",
headers,
withCredentials: true,
});
http.interceptors.request.use(injectToken, (error) =>
Promise.reject(error)
);
http.interceptors.response.use(
(response) => response,
(error) => {
const { response } = error;
return this.handleError(response);
}
);
this.instance = http;
return http;
}
request<T = any, R = AxiosResponse<T>>(
config: AxiosRequestConfig
): Promise<R> {
return this.http.request(config);
}
get<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.http.get<T, R>(url, config);
}
post<T = any, R = AxiosResponse<T>>(
url: string,
data?: T,
config?: AxiosRequestConfig
): Promise<R> {
return this.http.post<T, R>(url, data, config);
}
put<T = any, R = AxiosResponse<T>>(
url: string,
data?: T,
config?: AxiosRequestConfig
): Promise<R> {
return this.http.put<T, R>(url, data, config);
}
delete<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.http.delete<T, R>(url, config);
}
// Handle global app errors
// We can handle generic app errors depending on the status code
private handleError(error: any) {
const { status } = error;
switch (status) {
case StatusCode.InternalServerError: {
// Handle InternalServerError
break;
}
case StatusCode.Forbidden: {
// Handle Forbidden
break;
}
case StatusCode.Unauthorized: {
// Handle Unauthorized
break;
}
case StatusCode.TooManyRequests: {
// Handle TooManyRequests
break;
}
}
return Promise.reject(error);
}
}
export const http = new Http();
There is an ability to set different types to input an output data (axios definitions):
post<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
So, in your case it would be something like:
export interface UserRegistrationModel {
email: string;
password: string;
firstname: string;
lastname: string;
}
export const register = async (user: UserRegistrationModel) => {
const { data } = await http.post<UserRegistrationModel, AxiosResponse<{ accessToken: string }>>("/users", user);
return data;
};
Change your register function to:
export const register = async (user: UserRegistrationModel) => {
const { data } = await http.post<AuthModel>("/users", user);
return data;
};
Also inside your class, the type for post should be:
post<T = any>(
url: string,
data?: T,
config?: AxiosRequestConfig
): Promise<T> {
return this.http.post(url, data, config);
}
Property 'accessToken' does not exist on type 'UserRegistrationModel
You set the return type for data to be UserRegistrationModel, and typescript is telling you that accessToken does not exist on that type. This should be obvious from your definition.
Argument of type '(data: AuthModel) => void' is not assignable to parameter of type '(value: UserRegistrationModel) => void | PromiseLike'. Types of parameters 'data' and 'value' are incompatible. Property 'accessToken' is missing in type 'UserRegistrationModel' but required in type 'AuthModel'.
You are trying to pass a function which expects AuthModel as the only argument, but once again your register function will pass UserRegistrationModel to that function. Typescript is just informing you of this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With